Update //base to chromium 9659b08ea5a34f889dc4166217f438095ddc10d2

This updates our copy of //base to be based off of commit 9659b08ea by
performing the following commands:

1.) Check out //base at 9659b08ea
2.) Apply the //base portion of the following commits from mojo:

57ca940d8410a27fdf517b6194d7ecb0f29ecc2a
c3b05c507e712f4ee65522e0a00e38c735c85244
d3482c6d25faabd04dffcea32d4dee18af74d600
18a6ce7215ece72e4359600852bb0cf5fd87339f
a67383613f17083d918c31cf377932f5b43b91ab
0204e1a3a6679a0e634b66f661e23f424f044152
d423877725e8606e5ebac142e5c4b5c8c2dc4810
7a690c5c0344946ed74402d61d473502bc03ad77
cfeba3cce284f8a4d382337201d479768bb0eb77
df7f866ce3da1ef3c212cde977a6a77dc832ce22
57be778fd4d820b026165969352d7b40d476730b
34776a703d8cce41052e5a3867a23d8970fbb549
0f5eacecbe12aae15b114a8511ae718506431b37
c4ebd590b6e2749a4ab3f97fd49bbd3a4d510759

3.) Fix up the rest of the repo for //base API changes:
  *) StartsWith/EndsWith string functions are in base:: namespace and have
  slightly different options
  *) Tokenize replaced with base::SplitString
  *) MessageLoopProxy removed, use TaskRunner instead

4.) git cl format, gn format
5.) Delete OWNERS file import from //base/mac to //chrome/...

This puts mojo's copy at base very close to parity with the flutter engine's
copy.

R=viettrungluu@chromium.org

Review URL: https://codereview.chromium.org/1641513004 .
diff --git a/apps/benchmark/benchmark_app.cc b/apps/benchmark/benchmark_app.cc
index c467d4d..3f5c364 100644
--- a/apps/benchmark/benchmark_app.cc
+++ b/apps/benchmark/benchmark_app.cc
@@ -78,7 +78,7 @@
     }
     std::vector<std::string> unique_categories(category_set.begin(),
                                                category_set.end());
-    return JoinString(unique_categories, ',');
+    return base::JoinString(unique_categories, ",");
   }
 
   void StartTracedApplication(mojo::ApplicationImpl* app) {
diff --git a/apps/benchmark/event_unittest.cc b/apps/benchmark/event_unittest.cc
index 9bb60f7..442d78d 100644
--- a/apps/benchmark/event_unittest.cc
+++ b/apps/benchmark/event_unittest.cc
@@ -94,7 +94,7 @@
       "event\"}";
   event_specs[5] = "{\"tid\":1,\"ts\":6,\"ph\":\"E\"}";
 
-  std::string trace_json = "[" + JoinString(event_specs, ',') + "]";
+  std::string trace_json = "[" + base::JoinString(event_specs, ",") + "]";
   std::vector<Event> events;
   ASSERT_TRUE(GetEvents(trace_json, &events));
   ASSERT_EQ(3u, events.size());
@@ -127,7 +127,7 @@
   event_specs[2] = "{\"tid\":1,\"ts\":3,\"ph\":\"E\"}";
   event_specs[3] = "{\"tid\":2,\"ts\":4,\"ph\":\"E\"}";
 
-  std::string trace_json = "[" + JoinString(event_specs, ',') + "]";
+  std::string trace_json = "[" + base::JoinString(event_specs, ",") + "]";
   std::vector<Event> events;
   ASSERT_TRUE(GetEvents(trace_json, &events));
   ASSERT_EQ(2u, events.size());
@@ -152,7 +152,7 @@
       "\"name\":\"t1 event\"}";
   event_specs[1] = "{\"tid\":\"1\",\"ts\":3,\"ph\":\"E\"}";
 
-  std::string trace_json = "[" + JoinString(event_specs, ',') + "]";
+  std::string trace_json = "[" + base::JoinString(event_specs, ",") + "]";
   std::vector<Event> events;
   ASSERT_TRUE(GetEvents(trace_json, &events));
   ASSERT_EQ(1u, events.size());
@@ -179,7 +179,7 @@
       "{\"tid\":1004,\"id\":2,\"ts\":4,\"ph\":\"F\",\"cat\":\"cc\",\"name\":"
       "\"t2 event\"}";
 
-  std::string trace_json = "[" + JoinString(event_specs, ',') + "]";
+  std::string trace_json = "[" + base::JoinString(event_specs, ",") + "]";
   std::vector<Event> events;
   ASSERT_TRUE(GetEvents(trace_json, &events));
   ASSERT_EQ(2u, events.size());
@@ -206,7 +206,7 @@
       "{\"tid\":1003,\"id\":\"a\",\"ts\":3,\"ph\":\"F\",\"cat\":\"cc\","
       "\"name\":\"t1 event\"}";
 
-  std::string trace_json = "[" + JoinString(event_specs, ',') + "]";
+  std::string trace_json = "[" + base::JoinString(event_specs, ",") + "]";
   std::vector<Event> events;
   ASSERT_TRUE(GetEvents(trace_json, &events));
   ASSERT_EQ(1u, events.size());
diff --git a/base/BUILD.gn b/base/BUILD.gn
index eff163a..02d0bf9 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -39,7 +39,7 @@
     "base_paths_win.h",
   ]
 
-  if (is_android || is_mac) {
+  if (is_android || is_mac || is_ios) {
     sources -= [ "base_paths_posix.cc" ]
   }
 
@@ -83,6 +83,7 @@
     "android/content_uri_utils.cc",
     "android/content_uri_utils.h",
     "android/cpu_features.cc",
+    "android/cxa_demangle_stub.cc",
     "android/event_log.cc",
     "android/event_log.h",
     "android/field_trial_list.cc",
@@ -139,11 +140,8 @@
     "atomic_ref_count.h",
     "atomic_sequence_num.h",
     "atomicops.h",
-    "atomicops_internals_gcc.h",
     "atomicops_internals_mac.h",
     "atomicops_internals_portable.h",
-    "atomicops_internals_x86_gcc.cc",
-    "atomicops_internals_x86_gcc.h",
     "atomicops_internals_x86_msvc.h",
     "auto_reset.h",
     "barrier_closure.cc",
@@ -177,6 +175,7 @@
     "containers/linked_list.h",
     "containers/mru_cache.h",
     "containers/scoped_ptr_hash_map.h",
+    "containers/scoped_ptr_map.h",
     "containers/small_map.h",
     "containers/stack_container.h",
     "cpu.cc",
@@ -270,6 +269,9 @@
     "mac/bind_objc_block.h",
     "mac/bundle_locations.h",
     "mac/bundle_locations.mm",
+    "mac/call_with_eh_frame.cc",
+    "mac/call_with_eh_frame.h",
+    "mac/call_with_eh_frame_asm.S",
     "mac/cocoa_protocols.h",
     "mac/dispatch_source_mach.cc",
     "mac/dispatch_source_mach.h",
@@ -320,10 +322,8 @@
     "message_loop/incoming_task_queue.h",
     "message_loop/message_loop.cc",
     "message_loop/message_loop.h",
-    "message_loop/message_loop_proxy.cc",
-    "message_loop/message_loop_proxy.h",
-    "message_loop/message_loop_proxy_impl.cc",
-    "message_loop/message_loop_proxy_impl.h",
+    "message_loop/message_loop_task_runner.cc",
+    "message_loop/message_loop_task_runner.h",
     "message_loop/message_pump.cc",
     "message_loop/message_pump.h",
     "message_loop/message_pump_android.cc",
@@ -364,7 +364,6 @@
     "pending_task.h",
     "pickle.cc",
     "pickle.h",
-    "port.h",
     "posix/eintr_wrapper.h",
     "posix/file_descriptor_shuffle.cc",
     "posix/global_descriptors.cc",
@@ -427,6 +426,8 @@
     "strings/latin1_string_conversions.h",
     "strings/nullable_string16.cc",
     "strings/nullable_string16.h",
+    "strings/pattern.cc",
+    "strings/pattern.h",
     "strings/safe_sprintf.cc",
     "strings/safe_sprintf.h",
     "strings/string16.cc",
@@ -642,6 +643,8 @@
     "sys_info_openbsd.cc",
   ]
 
+  data = []
+
   configs += [ ":base_implementation" ]
 
   deps = [
@@ -722,6 +725,11 @@
       "sys_info.cc",
       "sys_info_posix.cc",
     ]
+
+    # We build with a 10.9 min sdk version but lots of code in this directory is
+    # written to target a 10.6 min sdk version and thus depends on declarations
+    # marked as deprecated on 10.9+. Suppress these warnings for now.
+    cflags = [ "-Wno-deprecated-declarations" ]
   } else {
     # Remove NaCl stuff.
     sources -= [
@@ -742,6 +750,30 @@
       "sha1_win.cc",
     ]
 
+    # Required for base/stack_trace_win.cc to symbolize correctly.
+    data += [ "$root_build_dir/dbghelp.dll" ]
+
+    if (is_component_build) {
+      # Copy the VS runtime DLLs into the isolate so that they don't have to be
+      # preinstalled on the target machine. The debug runtimes have a "d" at
+      # the end.
+      if (is_debug) {
+        vcrt_suffix = "d"
+      } else {
+        vcrt_suffix = ""
+      }
+
+      # These runtime files are copied to the output directory by the
+      # vs_toolchain script that runs as part of toolchain configuration.
+      data += [
+        "$root_out_dir/msvcp120${vcrt_suffix}.dll",
+        "$root_out_dir/msvcr120${vcrt_suffix}.dll",
+      ]
+      if (is_asan) {
+        data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ]
+      }
+    }
+
     # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
     configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
@@ -758,17 +790,25 @@
   }
 
   # Mac.
-  if (is_mac) {
+  if (is_mac || is_ios) {
+    # Common Desktop / iOS excludes
     sources -= [
       "native_library_posix.cc",
       "strings/sys_string_conversions_posix.cc",
       "threading/platform_thread_internal_posix.cc",
     ]
 
-    # We build with a 10.9 min sdk version but lots of code in this directory is
-    # written to target a 10.6 min sdk version and thus depends on declarations
-    # marked as deprecated on 10.9+. Suppress these warnings for now.
-    cflags = [ "-Wno-deprecated-declarations" ]
+    if (is_asan) {
+      # TODO(GYP) hook up asan on Mac. GYP has this extra dylib:
+      #data += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ]
+    }
+
+    if (is_ios) {
+      sources -= [
+        "files/file_path_watcher_fsevents.cc",
+        "files/file_path_watcher_fsevents.h",
+      ]
+    }
   } else {
     # Non-Mac.
     sources -= [
@@ -781,6 +821,11 @@
 
   # Linux.
   if (is_linux) {
+    if (is_asan || is_lsan || is_msan || is_tsan) {
+      # For llvm-sanitizer.
+      data += [ "//third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6" ]
+    }
+
     # TODO(brettw) this will need to be parameterized at some point.
     linux_configs = []
 
@@ -810,8 +855,60 @@
     }
   }
 
+  # iOS
+  if (is_ios) {
+    set_sources_assignment_filter([])
+
+    sources += [
+      "atomicops_internals_mac.h",
+      "base_paths_mac.h",
+      "base_paths_mac.mm",
+      "file_version_info_mac.h",
+      "file_version_info_mac.mm",
+      "files/file_util_mac.mm",
+      "mac/bundle_locations.h",
+      "mac/bundle_locations.mm",
+      "mac/call_with_eh_frame.cc",
+      "mac/call_with_eh_frame.h",
+      "mac/foundation_util.h",
+      "mac/foundation_util.mm",
+      "mac/mac_logging.cc",
+      "mac/mac_logging.h",
+      "mac/mach_logging.cc",
+      "mac/mach_logging.h",
+      "mac/objc_property_releaser.h",
+      "mac/objc_property_releaser.mm",
+      "mac/scoped_mach_port.cc",
+      "mac/scoped_mach_port.h",
+      "mac/scoped_mach_vm.cc",
+      "mac/scoped_mach_vm.h",
+      "mac/scoped_nsautorelease_pool.h",
+      "mac/scoped_nsautorelease_pool.mm",
+      "mac/scoped_nsobject.h",
+      "mac/scoped_objc_class_swizzler.h",
+      "mac/scoped_objc_class_swizzler.mm",
+      "message_loop/message_pump_mac.h",
+      "message_loop/message_pump_mac.mm",
+      "strings/sys_string_conversions_mac.mm",
+      "threading/platform_thread_mac.mm",
+      "time/time_mac.cc",
+    ]
+
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (is_asan || is_lsan || is_msan || is_tsan) {
+    data += [ "//tools/valgrind/asan/" ]
+    if (is_win) {
+      data +=
+          [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer.exe" ]
+    } else {
+      data += [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer" ]
+    }
+  }
+
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
-  if (is_android && !is_debug) {
+  if (!is_debug) {
     configs -= [ "//build/config/compiler:optimize" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
@@ -830,7 +927,7 @@
     "win/pe_image.h",
   ]
 
-  if (is_android && !is_debug) {
+  if (!is_debug) {
     configs -= [ "//build/config/compiler:optimize" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
@@ -883,7 +980,7 @@
     "//third_party/icu",
   ]
 
-  if (is_android && !is_debug) {
+  if (!is_debug) {
     configs -= [ "//build/config/compiler:optimize" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
@@ -995,7 +1092,7 @@
     ":base",
   ]
 
-  if (is_android && !is_debug) {
+  if (!is_debug) {
     configs -= [ "//build/config/compiler:optimize" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
@@ -1056,6 +1153,15 @@
   }
 }
 
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("base_unittests_run") {
+  testonly = true
+  deps = [
+    ":base_unittests",
+  ]
+}
+
 test("base_unittests") {
   sources = [
     "android/application_status_listener_unittest.cc",
@@ -1089,6 +1195,7 @@
     "containers/linked_list_unittest.cc",
     "containers/mru_cache_unittest.cc",
     "containers/scoped_ptr_hash_map_unittest.cc",
+    "containers/scoped_ptr_map_unittest.cc",
     "containers/small_map_unittest.cc",
     "containers/stack_container_unittest.cc",
     "cpu_unittest.cc",
@@ -1136,6 +1243,7 @@
     "lazy_instance_unittest.cc",
     "logging_unittest.cc",
     "mac/bind_objc_block_unittest.mm",
+    "mac/call_with_eh_frame_unittest.mm",
     "mac/dispatch_source_mach_unittest.cc",
     "mac/foundation_util_unittest.mm",
     "mac/libdispatch_task_runner_unittest.cc",
@@ -1159,8 +1267,7 @@
     "memory/singleton_unittest.cc",
     "memory/weak_ptr_unittest.cc",
     "memory/weak_ptr_unittest.nc",
-    "message_loop/message_loop_proxy_impl_unittest.cc",
-    "message_loop/message_loop_proxy_unittest.cc",
+    "message_loop/message_loop_task_runner_unittest.cc",
     "message_loop/message_loop_unittest.cc",
     "message_loop/message_pump_io_ios_unittest.cc",
     "metrics/bucket_ranges_unittest.cc",
@@ -1211,6 +1318,7 @@
     "sha1_unittest.cc",
     "stl_util_unittest.cc",
     "strings/nullable_string16_unittest.cc",
+    "strings/pattern_unittest.cc",
     "strings/safe_sprintf_unittest.cc",
     "strings/string16_unittest.cc",
     "strings/string_number_conversions_unittest.cc",
@@ -1308,9 +1416,6 @@
 
   data = [
     "test/data/",
-
-    # TODO(dpranke): Remove when icu declares this directly.
-    "$root_out_dir/icudtl.dat",
   ]
 
   # Allow more direct string conversions on platforms with native utf8
@@ -1324,14 +1429,15 @@
       ":base_java",
       ":base_java_unittest_support",
     ]
+
+    # TODO(brettw) I think this should not be here, we should not be using
+    # isolate files.
     isolate_file = "base_unittests.isolate"
   }
 
   if (is_ios) {
     sources -= [
       "process/memory_unittest.cc",
-      "process/memory_unittest_mac.h",
-      "process/memory_unittest_mac.mm",
       "process/process_unittest.cc",
       "process/process_util_unittest.cc",
     ]
@@ -1371,6 +1477,15 @@
 
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  # Symbols for crashes when running tests on swarming.
+  if (symbol_level > 0) {
+    if (is_win) {
+      data += [ "$root_out_dir/base_unittests.exe.pdb" ]
+    } else if (is_mac) {
+      data += [ "$root_out_dir/base_unittests.dSYM/" ]
+    }
+  }
 }
 
 if (is_android) {
diff --git a/base/OWNERS b/base/OWNERS
index 9890491..bcaa81b 100644
--- a/base/OWNERS
+++ b/base/OWNERS
@@ -1,13 +1,9 @@
 mark@chromium.org
-darin@chromium.org
 thakis@chromium.org
 danakj@chromium.org
 rvargas@chromium.org
 thestig@chromium.org
 
-# On extended leave.
-willchan@chromium.org
-
 # Chromium is a very mature project, most things that are generally useful are
 # already here, and that things not here aren't generally useful.
 #
@@ -21,8 +17,9 @@
 # writing the stuff you want to log in a regular logging statement, even
 # if it makes your calling code longer. Just add it to your own code.
 
-per-file *.isolate=csharp@chromium.org
 per-file *.isolate=maruel@chromium.org
+per-file *.isolate=tandrii@chromium.org
+per-file *.isolate=vadimsh@chromium.org
 per-file security_unittest.cc=jln@chromium.org
 
 # For Android-specific changes:
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index a07a356..c42de1a 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -63,6 +63,17 @@
       "$tcmalloc_dir/src/base/abort.cc",
       "$tcmalloc_dir/src/base/abort.h",
       "$tcmalloc_dir/src/base/arm_instruction_set_select.h",
+      "$tcmalloc_dir/src/base/atomicops-internals-arm-generic.h",
+      "$tcmalloc_dir/src/base/atomicops-internals-arm-v6plus.h",
+      "$tcmalloc_dir/src/base/atomicops-internals-linuxppc.h",
+      "$tcmalloc_dir/src/base/atomicops-internals-macosx.h",
+      "$tcmalloc_dir/src/base/atomicops-internals-windows.h",
+      "$tcmalloc_dir/src/base/atomicops-internals-x86.cc",
+      "$tcmalloc_dir/src/base/atomicops-internals-x86.h",
+      "$tcmalloc_dir/src/base/atomicops.h",
+      "$tcmalloc_dir/src/base/basictypes.h",
+      "$tcmalloc_dir/src/base/commandlineflags.h",
+      "$tcmalloc_dir/src/base/cycleclock.h",
 
       # We don't list dynamic_annotations.c since its copy is already
       # present in the dynamic_annotations target.
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
index 4d3cd55..93667ef 100644
--- a/base/android/build_info.cc
+++ b/base/android/build_info.cc
@@ -48,20 +48,21 @@
       model_(StrDupJString(Java_BuildInfo_getDeviceModel(env))),
       brand_(StrDupJString(Java_BuildInfo_getBrand(env))),
       android_build_id_(StrDupJString(Java_BuildInfo_getAndroidBuildId(env))),
-      android_build_fp_(StrDupJString(
-          Java_BuildInfo_getAndroidBuildFingerprint(env))),
-      package_version_code_(StrDupJString(Java_BuildInfo_getPackageVersionCode(
-          env, GetApplicationContext()))),
-      package_version_name_(StrDupJString(Java_BuildInfo_getPackageVersionName(
-          env, GetApplicationContext()))),
-      package_label_(StrDupJString(Java_BuildInfo_getPackageLabel(
-          env, GetApplicationContext()))),
-      package_name_(StrDupJString(Java_BuildInfo_getPackageName(
-          env, GetApplicationContext()))),
+      android_build_fp_(
+          StrDupJString(Java_BuildInfo_getAndroidBuildFingerprint(env))),
+      package_version_code_(StrDupJString(
+          Java_BuildInfo_getPackageVersionCode(env, GetApplicationContext()))),
+      package_version_name_(StrDupJString(
+          Java_BuildInfo_getPackageVersionName(env, GetApplicationContext()))),
+      package_label_(StrDupJString(
+          Java_BuildInfo_getPackageLabel(env, GetApplicationContext()))),
+      package_name_(StrDupJString(
+          Java_BuildInfo_getPackageName(env, GetApplicationContext()))),
       build_type_(StrDupJString(Java_BuildInfo_getBuildType(env))),
       sdk_int_(Java_BuildInfo_getSdkInt(env)),
-      java_exception_info_(NULL) {
-}
+      has_language_apk_splits_(
+          Java_BuildInfo_hasLanguageApkSplits(env, GetApplicationContext())),
+      java_exception_info_(NULL) {}
 
 // static
 BuildInfo* BuildInfo::GetInstance() {
diff --git a/base/android/build_info.h b/base/android/build_info.h
index 093b832..0d722b5 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -96,6 +96,8 @@
     return sdk_int_;
   }
 
+  int has_language_apk_splits() const { return has_language_apk_splits_; }
+
   const char* java_exception_info() const {
     return java_exception_info_;
   }
@@ -127,6 +129,7 @@
   const char* const package_name_;
   const char* const build_type_;
   const int sdk_int_;
+  const bool has_language_apk_splits_;
   // This is set via set_java_exception_info, not at constructor time.
   const char* java_exception_info_;
 
diff --git a/base/android/cxa_demangle_stub.cc b/base/android/cxa_demangle_stub.cc
new file mode 100644
index 0000000..b0d2b87
--- /dev/null
+++ b/base/android/cxa_demangle_stub.cc
@@ -0,0 +1,19 @@
+// 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 <unistd.h>
+
+// LLVM's demangler is large, and we have no need of it.  Overriding it with
+// our own stub version here stops a lot of code being pulled in from libc++.
+// More here:
+//   https://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp
+extern "C" char* __cxa_demangle(const char* mangled_name,
+                                char* buf,
+                                size_t* n,
+                                int* status) {
+  static const int kMemoryAllocFailure = -1;  // LLVM's memory_alloc_failure.
+  if (status)
+    *status = kMemoryAllocFailure;
+  return nullptr;
+}
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
index d7c7b05..8ec4afa 100644
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -8,7 +8,6 @@
 import android.app.Application;
 import android.content.Context;
 import android.os.Bundle;
-import android.view.KeyEvent;
 import android.view.Window;
 
 import java.lang.reflect.InvocationHandler;
@@ -38,9 +37,6 @@
     /**
      * Intercepts calls to an existing Window.Callback. Most invocations are passed on directly
      * to the composed Window.Callback but enables intercepting/manipulating others.
-     *
-     * This is used to relay window focus changes throughout the app and remedy a bug in the
-     * appcompat library.
      */
     private class WindowCallbackProxy implements InvocationHandler {
         private final Window.Callback mCallback;
@@ -57,9 +53,6 @@
                     && args[0] instanceof Boolean) {
                 onWindowFocusChanged((boolean) args[0]);
                 return null;
-            } else if (method.getName().equals("dispatchKeyEvent") && args.length == 1
-                    && args[0] instanceof KeyEvent) {
-                return dispatchKeyEvent((KeyEvent) args[0]);
             } else {
                 try {
                     return method.invoke(mCallback, args);
@@ -85,15 +78,6 @@
                 listener.onWindowFocusChanged(mActivity, hasFocus);
             }
         }
-
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals
-            // KEYCODE_MENU. (see b/20529185)
-            if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && mActivity.dispatchKeyEvent(event)) {
-                return true;
-            }
-            return mCallback.dispatchKeyEvent(event);
-        }
     }
     @Override
     public void onCreate() {
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index 54f611d..1b91d39 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -4,12 +4,14 @@
 
 package org.chromium.base;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
+import android.text.TextUtils;
 import android.util.Log;
 
 /**
@@ -122,4 +124,35 @@
     public static int getSdkInt() {
         return Build.VERSION.SDK_INT;
     }
+
+    /**
+     * @return Whether the Android build is M or later.
+     */
+    public static boolean isMncOrLater() {
+        // TODO(bauerb): Update this once the SDK is updated.
+        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1
+                || TextUtils.equals("MNC", Build.VERSION.CODENAME);
+    }
+
+    private static boolean isLanguageSplit(String splitName) {
+        // Names look like "config.XX".
+        return splitName.length() == 9 && splitName.startsWith("config.");
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    @CalledByNative
+    public static boolean hasLanguageApkSplits(Context context) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return false;
+        }
+        PackageInfo packageInfo = PackageUtils.getOwnPackageInfo(context);
+        if (packageInfo.splitNames != null) {
+            for (int i = 0; i < packageInfo.splitNames.length; ++i) {
+                if (isLanguageSplit(packageInfo.splitNames[i])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/CollectionUtil.java b/base/android/java/src/org/chromium/base/CollectionUtil.java
index 4a4c754..2672d65 100644
--- a/base/android/java/src/org/chromium/base/CollectionUtil.java
+++ b/base/android/java/src/org/chromium/base/CollectionUtil.java
@@ -31,6 +31,7 @@
         return list;
     }
 
+    @VisibleForTesting
     public static <E> ArrayList<E> newArrayList(Iterable<E> iterable) {
         ArrayList<E> list = new ArrayList<E>();
         for (E element : iterable) {
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
index c83cfe7..3b46cdc 100644
--- a/base/android/java/src/org/chromium/base/Log.java
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -4,9 +4,7 @@
 
 package org.chromium.base;
 
-import android.text.TextUtils;
-
-import org.chromium.base.annotations.NoSideEffects;
+import org.chromium.base.annotations.RemovableInRelease;
 
 import java.util.Locale;
 
@@ -62,27 +60,6 @@
         return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, params);
     }
 
-    /**
-     * Returns a full tag for the provided group tag. Full tags longer than 23 characters
-     * will cause a runtime exception.
-     *
-     * @param groupTag {@code null} and empty string are allowed.
-     *
-     * @see android.util.Log#isLoggable(String, int)
-     * @throws IllegalArgumentException if the tag is too long.
-     * @deprecated Directly use a string (e.g. "cr.Tag") in your class. See http://crbug.com/485772
-     */
-    @Deprecated
-    public static String makeTag(String groupTag) {
-        if (TextUtils.isEmpty(groupTag)) return "cr";
-        String tag = "cr." + groupTag;
-        if (tag.length() > 23) {
-            throw new IllegalArgumentException(
-                    "The full tag (" + tag + ") is longer than 23 characters.");
-        }
-        return tag;
-    }
-
     /** Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}. */
     public static boolean isLoggable(String tag, int level) {
         return android.util.Log.isLoggable(tag, level);
@@ -93,7 +70,7 @@
      *
      * For optimization purposes, only the fixed parameters versions are visible. If you need more
      * than 7 parameters, consider building your log message using a function annotated with
-     * {@link NoSideEffects}.
+     * {@link RemovableInRelease}.
      *
      * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
@@ -102,7 +79,7 @@
      *             one is a {@link Throwable}, its trace will be printed.
      */
     private static void verbose(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
+        if (Log.isLoggable(tag, Log.VERBOSE)) {
             String message = formatLogWithStack(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -113,46 +90,62 @@
         }
     }
 
-    /** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 0 args version. */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String message) {
         verbose(tag, message);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String messageTemplate, Object arg1) {
         verbose(tag, messageTemplate, arg1);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String messageTemplate, Object arg1, Object arg2) {
         verbose(tag, messageTemplate, arg1, arg2);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(
             String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
         verbose(tag, messageTemplate, arg1, arg2, arg3);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4) {
         verbose(tag, messageTemplate, arg1, arg2, arg3, arg4);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4, Object arg5) {
         verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4, Object arg5, Object arg6) {
         verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4, Object arg5, Object arg6, Object arg7) {
         verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
@@ -163,7 +156,7 @@
      *
      * For optimization purposes, only the fixed parameters versions are visible. If you need more
      * than 7 parameters, consider building your log message using a function annotated with
-     * {@link NoSideEffects}.
+     * {@link RemovableInRelease}.
      *
      * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
@@ -172,7 +165,7 @@
      *             one is a {@link Throwable}, its trace will be printed.
      */
     private static void debug(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
+        if (isLoggable(tag, Log.DEBUG)) {
             String message = formatLogWithStack(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -183,44 +176,60 @@
         }
     }
 
-    /** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
+    /** Sends a {@link android.util.Log#DEBUG} log message. 0 args version. */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String message) {
         debug(tag, message);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String messageTemplate, Object arg1) {
         debug(tag, messageTemplate, arg1);
     }
     /** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String messageTemplate, Object arg1, Object arg2) {
         debug(tag, messageTemplate, arg1, arg2);
     }
     /** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(
             String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
         debug(tag, messageTemplate, arg1, arg2, arg3);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4) {
         debug(tag, messageTemplate, arg1, arg2, arg3, arg4);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4, Object arg5) {
         debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4, Object arg5, Object arg6) {
         debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
             Object arg4, Object arg5, Object arg6, Object arg7) {
         debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
@@ -235,8 +244,9 @@
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
+    @VisibleForTesting
     public static void i(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.INFO)) {
+        if (Log.isLoggable(tag, Log.INFO)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -256,8 +266,9 @@
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
+    @VisibleForTesting
     public static void w(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.WARN)) {
+        if (Log.isLoggable(tag, Log.WARN)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -277,8 +288,9 @@
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
+    @VisibleForTesting
     public static void e(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
+        if (Log.isLoggable(tag, Log.ERROR)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -302,8 +314,9 @@
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
+    @VisibleForTesting
     public static void wtf(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
+        if (Log.isLoggable(tag, Log.ASSERT)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
index e7c2030..7979287 100644
--- a/base/android/java/src/org/chromium/base/MemoryPressureListener.java
+++ b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
@@ -72,10 +72,10 @@
         } else if (ACTION_TRIM_MEMORY.equals(action)) {
             simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
         } else if (ACTION_TRIM_MEMORY_RUNNING_CRITICAL.equals(action)) {
-            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
-        } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
             simulateTrimMemoryPressureSignal(activity,
                     ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL);
+        } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
         } else {
             return false;
         }
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index e46fc30..77affe1 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -9,12 +9,14 @@
 import android.os.AsyncTask;
 import android.os.Environment;
 
+import java.io.File;
 import java.util.concurrent.ExecutionException;
 
 /**
  * This class provides the path related methods for the native library.
  */
 public abstract class PathUtils {
+    private static final String THUMBNAIL_DIRECTORY = "textures";
 
     private static final int DATA_DIRECTORY = 0;
     private static final int DATABASE_DIRECTORY = 1;
@@ -22,6 +24,8 @@
     private static final int NUM_DIRECTORIES = 3;
     private static AsyncTask<String, Void, String[]> sDirPathFetchTask;
 
+    private static File sThumbnailDirectory;
+
     // Prevent instantiation.
     private PathUtils() {}
 
@@ -91,6 +95,18 @@
         return getDirectoryPath(CACHE_DIRECTORY);
     }
 
+    public static File getThumbnailCacheDirectory(Context appContext) {
+        if (sThumbnailDirectory == null) {
+            sThumbnailDirectory = appContext.getDir(THUMBNAIL_DIRECTORY, Context.MODE_PRIVATE);
+        }
+        return sThumbnailDirectory;
+    }
+
+    @CalledByNative
+    public static String getThumbnailCacheDirectoryPath(Context appContext) {
+        return getThumbnailCacheDirectory(appContext).getAbsolutePath();
+    }
+
     /**
      * @return the public downloads directory.
      */
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
index a795b6b..6104bf0 100644
--- a/base/android/java/src/org/chromium/base/README_logging.md
+++ b/base/android/java/src/org/chromium/base/README_logging.md
@@ -43,6 +43,20 @@
 Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`
 By default, the level for all tags is `INFO`.
 
+### An exception trace is printed when the exception is the last parameter ###
+
+As with `java.util.Log`, putting a throwable as last parameter will dump the corresponding stack
+trace:
+
+    Log.i(TAG, "An error happened: %s", e)
+
+    I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message
+    I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
+    I/cr.YourModuleTag: ( 999):     at foo.bar.MyClass.test(MyClass.java:42)
+    I/cr.YourModuleTag: ( 999):     ...
+
+Having the exception as last parameter doesn't prevent it from being used for string formatting.
+
 ### Logging Best Practices
 
 #### Rule #1: Never log PII (Personal Identification Information):
@@ -111,7 +125,7 @@
     while the previous method can enable or disable debugging for a whole feature without changing
     any source file.
 
--   Annotate debug functions with the `@NoSideEffects` annotation.
+-   Annotate debug functions with the `@RemovableInRelease` annotation.
 
     That annotation tells Proguard to assume that a given function has no side effects, and is
     called only for its returned value. If this value is unused, the call will be removed. If the
@@ -121,7 +135,7 @@
   
         /* If that function is only used in Log.d calls, proguard should completely remove it from
          * the release builds. */
-        @NoSideEffects
+        @RemovableInRelease
         private static String getSomeDebugLogString(Thing[] things) {
           /* Still needs to be guarded to avoid impacting debug builds, or in case it's used for
            * some other log levels. But at least it is done only once, inside the function. */
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
index d44f2fc..030dcf9 100644
--- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -6,18 +6,17 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.res.AssetManager;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Trace;
-import android.preference.PreferenceManager;
 import android.util.Log;
 
+import org.chromium.base.annotations.SuppressFBWarnings;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FilenameFilter;
@@ -28,7 +27,6 @@
 import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
-import java.util.regex.Pattern;
 
 /**
  * Handles extracting the necessary resources bundled in an APK and moving them to a location on
@@ -37,23 +35,25 @@
 public class ResourceExtractor {
 
     private static final String LOGTAG = "ResourceExtractor";
-    private static final String LAST_LANGUAGE = "Last language";
-    private static final String PAK_FILENAMES_LEGACY_NOREUSE = "Pak filenames";
     private static final String ICU_DATA_FILENAME = "icudtl.dat";
     private static final String V8_NATIVES_DATA_FILENAME = "natives_blob.bin";
     private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
 
-    private static String[] sMandatoryPaks = null;
+    private static ResourceEntry[] sResourcesToExtract = new ResourceEntry[0];
 
-    // By default, we attempt to extract a pak file for the users
-    // current device locale. Use setExtractImplicitLocale() to
-    // change this behavior.
-    private static boolean sExtractImplicitLocalePak = true;
+    /**
+     * Holds information about a res/raw file (e.g. locale .pak files).
+     */
+    public static final class ResourceEntry {
+        public final int resourceId;
+        public final String pathWithinApk;
+        public final String extractedFileName;
 
-    private static boolean isAppDataFile(String file) {
-        return ICU_DATA_FILENAME.equals(file)
-                || V8_NATIVES_DATA_FILENAME.equals(file)
-                || V8_SNAPSHOT_DATA_FILENAME.equals(file);
+        public ResourceEntry(int resourceId, String pathWithinApk, String extractedFileName) {
+            this.resourceId = resourceId;
+            this.pathWithinApk = pathWithinApk;
+            this.extractedFileName = extractedFileName;
+        }
     }
 
     private class ExtractTask extends AsyncTask<Void, Void, Void> {
@@ -61,12 +61,38 @@
 
         private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
 
-        public ExtractTask() {
+        private void extractResourceHelper(InputStream is, File outFile, byte[] buffer)
+                throws IOException {
+            OutputStream os = null;
+            try {
+                os = new FileOutputStream(outFile);
+                Log.i(LOGTAG, "Extracting resource " + outFile);
+
+                int count = 0;
+                while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
+                    os.write(buffer, 0, count);
+                }
+                os.flush();
+
+                // Ensure something reasonable was written.
+                if (outFile.length() == 0) {
+                    throw new IOException(outFile + " extracted with 0 length!");
+                }
+            } finally {
+                try {
+                    if (is != null) {
+                        is.close();
+                    }
+                } finally {
+                    if (os != null) {
+                        os.close();
+                    }
+                }
+            }
         }
 
         private void doInBackgroundImpl() {
             final File outputDir = getOutputDir();
-            final File appDataDir = getAppDataDir();
             if (!outputDir.exists() && !outputDir.mkdirs()) {
                 Log.e(LOGTAG, "Unable to create pak resources directory!");
                 return;
@@ -83,97 +109,22 @@
                 deleteFiles();
             }
 
-            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
-            String currentLocale = LocaleUtils.getDefaultLocale();
-            String currentLanguage = currentLocale.split("-", 2)[0];
-            // If everything we need is already there (and the locale hasn't
-            // changed), quick exit.
-            if (prefs.getString(LAST_LANGUAGE, "").equals(currentLanguage)) {
-                boolean filesPresent = true;
-                for (String file : sMandatoryPaks) {
-                    File directory = isAppDataFile(file) ? appDataDir : outputDir;
-                    if (!new File(directory, file).exists()) {
-                        filesPresent = false;
-                        break;
-                    }
-                }
-                if (filesPresent) return;
-            } else {
-                prefs.edit().putString(LAST_LANGUAGE, currentLanguage).apply();
-            }
-
-            StringBuilder p = new StringBuilder();
-            for (String mandatoryPak : sMandatoryPaks) {
-                if (p.length() > 0) p.append('|');
-                p.append("\\Q" + mandatoryPak + "\\E");
-            }
-
-            if (sExtractImplicitLocalePak) {
-                if (p.length() > 0) p.append('|');
-                // As well as the minimum required set of .paks above, we'll
-                // also add all .paks that we have for the user's currently
-                // selected language.
-                p.append(currentLanguage);
-                p.append("(-\\w+)?\\.pak");
-            }
-
-            Pattern paksToInstall = Pattern.compile(p.toString());
-
-            AssetManager manager = mContext.getResources().getAssets();
             beginTraceSection("WalkAssets");
+            byte[] buffer = new byte[BUFFER_SIZE];
             try {
-                // Loop through every asset file that we have in the APK, and look for the
-                // ones that we need to extract by trying to match the Patterns that we
-                // created above.
-                byte[] buffer = null;
-                String[] files = manager.list("");
-                for (String file : files) {
-                    if (!paksToInstall.matcher(file).matches()) {
-                        continue;
-                    }
-                    File output = new File(isAppDataFile(file) ? appDataDir : outputDir, file);
+                // Extract all files that don't already exist.
+                for (ResourceEntry entry : sResourcesToExtract) {
+                    File output = new File(outputDir, entry.extractedFileName);
                     if (output.exists()) {
                         continue;
                     }
-
-                    InputStream is = null;
-                    OutputStream os = null;
                     beginTraceSection("ExtractResource");
+                    InputStream inputStream =
+                            mContext.getResources().openRawResource(entry.resourceId);
                     try {
-                        is = manager.open(file);
-                        os = new FileOutputStream(output);
-                        Log.i(LOGTAG, "Extracting resource " + file);
-                        if (buffer == null) {
-                            buffer = new byte[BUFFER_SIZE];
-                        }
-
-                        int count = 0;
-                        while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
-                            os.write(buffer, 0, count);
-                        }
-                        os.flush();
-
-                        // Ensure something reasonable was written.
-                        if (output.length() == 0) {
-                            throw new IOException(file + " extracted with 0 length!");
-                        }
-
-                        if (isAppDataFile(file)) {
-                            // icu and V8 data need to be accessed by a renderer
-                            // process.
-                            output.setReadable(true, false);
-                        }
+                        extractResourceHelper(inputStream, output, buffer);
                     } finally {
-                        try {
-                            if (is != null) {
-                                is.close();
-                            }
-                        } finally {
-                            if (os != null) {
-                                os.close();
-                            }
-                            endTraceSection(); // ExtractResource
-                        }
+                        endTraceSection(); // ExtractResource
                     }
                 }
             } catch (IOException e) {
@@ -303,53 +254,19 @@
     }
 
     /**
-     * Specifies the .pak files that should be extracted from the APK's asset resources directory
-     * and moved to {@link #getOutputDirFromContext(Context)}.
-     * @param mandatoryPaks The list of pak files to be loaded. If no pak files are
-     *     required, pass a single empty string.
+     * Specifies the files that should be extracted from the APK.
+     * and moved to {@link #getOutputDir()}.
      */
-    public static void setMandatoryPaksToExtract(String... mandatoryPaks) {
+    @SuppressFBWarnings("EI_EXPOSE_STATIC_REP2")
+    public static void setResourcesToExtract(ResourceEntry[] entries) {
         assert (sInstance == null || sInstance.mExtractTask == null)
                 : "Must be called before startExtractingResources is called";
-        sMandatoryPaks = mandatoryPaks;
-
+        sResourcesToExtract = entries;
     }
 
-    /**
-     * By default the ResourceExtractor will attempt to extract a pak resource for the users
-     * currently specified locale. This behavior can be changed with this function and is
-     * only needed by tests.
-     * @param extract False if we should not attempt to extract a pak file for
-     *         the users currently selected locale and try to extract only the
-     *         pak files specified in sMandatoryPaks.
-     */
-    @VisibleForTesting
-    public static void setExtractImplicitLocaleForTesting(boolean extract) {
-        assert (sInstance == null || sInstance.mExtractTask == null)
-                : "Must be called before startExtractingResources is called";
-        sExtractImplicitLocalePak = extract;
-    }
-
-    /**
-     * Marks all the 'pak' resources, packaged as assets, for extraction during
-     * running the tests.
-     */
-    @VisibleForTesting
-    public void setExtractAllPaksAndV8SnapshotForTesting() {
-        List<String> pakAndSnapshotFileAssets = new ArrayList<String>();
-        AssetManager manager = mContext.getResources().getAssets();
-        try {
-            String[] files = manager.list("");
-            for (String file : files) {
-                if (file.endsWith(".pak")) pakAndSnapshotFileAssets.add(file);
-            }
-        } catch (IOException e) {
-            Log.w(LOGTAG, "Exception while accessing assets: " + e.getMessage(), e);
-        }
-        pakAndSnapshotFileAssets.add("natives_blob.bin");
-        pakAndSnapshotFileAssets.add("snapshot_blob.bin");
-        setMandatoryPaksToExtract(pakAndSnapshotFileAssets.toArray(
-                new String[pakAndSnapshotFileAssets.size()]));
+    // TODO(agrieve): Delete this method ones all usages of it are updated.
+    public static void setMandatoryPaksToExtract(String... paths) {
+        assert paths.length == 1 && "".equals(paths[0]);
     }
 
     private ResourceExtractor(Context context) {
@@ -421,6 +338,10 @@
             return;
         }
 
+        // If a previous release extracted resources, and the current release does not,
+        // deleteFiles() will not run and some files will be left. This currently
+        // can happen for ContentShell, but not for Chrome proper, since we always extract
+        // locale pak files.
         if (shouldSkipPakExtraction()) {
             return;
         }
@@ -473,12 +394,9 @@
     }
 
     /**
-     * Pak extraction not necessarily required by the embedder; we allow them to skip
-     * this process if they call setMandatoryPaksToExtract with a single empty String.
+     * Pak extraction not necessarily required by the embedder.
      */
     private static boolean shouldSkipPakExtraction() {
-        // Must call setMandatoryPaksToExtract before beginning resource extraction.
-        assert sMandatoryPaks != null;
-        return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]);
+        return sResourcesToExtract.length == 0;
     }
 }
diff --git a/base/android/java/src/org/chromium/base/StreamUtil.java b/base/android/java/src/org/chromium/base/StreamUtil.java
new file mode 100644
index 0000000..f8cbfee
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/StreamUtil.java
@@ -0,0 +1,28 @@
+// Copyright 2013 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.
+
+package org.chromium.base;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Helper methods to deal with stream related tasks.
+ */
+public class StreamUtil {
+    /**
+     * Handle closing a {@link java.io.Closeable} via {@link java.io.Closeable#close()} and catch
+     * the potentially thrown {@link java.io.IOException}.
+     * @param closeable The Closeable to be closed.
+     */
+    public static void closeQuietly(Closeable closeable) {
+        if (closeable == null) return;
+
+        try {
+            closeable.close();
+        } catch (IOException ex) {
+            // Ignore the exception on close.
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index c0b9172..647e33e 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -29,6 +29,7 @@
         }
     }
 
+    @VisibleForTesting
     public static void setUiThread(Looper looper) {
         synchronized (sLock) {
             if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
index 3d3b11a..9ace4a1 100644
--- a/base/android/java/src/org/chromium/base/TraceEvent.java
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -20,6 +20,7 @@
 public class TraceEvent {
 
     private static volatile boolean sEnabled = false;
+    private static volatile boolean sATraceEnabled = false; // True when taking an Android systrace.
 
     private static class BasicLooperMonitor implements Printer {
         @Override
@@ -176,6 +177,8 @@
     @CalledByNative
     public static void setEnabled(boolean enabled) {
         sEnabled = enabled;
+        // Android M+ systrace logs this on its own. Only log it if not writing to Android systrace.
+        if (sATraceEnabled) return;
         ThreadUtils.getUiThreadLooper().setMessageLogging(
                 enabled ? LooperMonitorHolder.sInstance : null);
     }
@@ -186,10 +189,15 @@
      * systrace, this is for WebView only.
      */
     public static void setATraceEnabled(boolean enabled) {
-        if (sEnabled == enabled) return;
+        if (sATraceEnabled == enabled) return;
+        sATraceEnabled = enabled;
         if (enabled) {
+            // Calls TraceEvent.setEnabled(true) via
+            // TraceLog::EnabledStateObserver::OnTraceLogEnabled
             nativeStartATrace();
         } else {
+            // Calls TraceEvent.setEnabled(false) via
+            // TraceLog::EnabledStateObserver::OnTraceLogDisabled
             nativeStopATrace();
         }
     }
diff --git a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
deleted file mode 100644
index 803c3f9..0000000
--- a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
+++ /dev/null
@@ -1,17 +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.
-
-package org.chromium.base.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Annotation used to indicate to proguard methods that have no side effects and can be
- * safely removed if their return value is not used. This is to be used with
- * {@link org.chromium.base.Log}'s method, that can also be removed by proguard. That way
- * expensive calls can be left in debug builds but removed in release.
- */
-@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
-public @interface NoSideEffects {}
diff --git a/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java b/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java
new file mode 100644
index 0000000..2191334
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * The annotated function can be removed in release builds.
+ *
+ * Calls to this function will be removed if its return value is not used. If all calls are removed,
+ * the function definition itself will be candidate for removal.
+ * It works by indicating to Proguard that the function has no side effects.
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface RemovableInRelease {}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java b/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java
new file mode 100644
index 0000000..81ac754
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java
@@ -0,0 +1,736 @@
+// 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.
+
+package org.chromium.base.library_loader;
+
+import android.os.Bundle;
+import android.os.Parcel;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.Log;
+import org.chromium.base.SysUtils;
+import org.chromium.base.ThreadUtils;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/*
+ * For more, see Technical note, Security considerations, and the explanation
+ * of how this class is supposed to be used in Linker.java.
+ */
+
+/**
+ * Provides a concrete implementation of the Chromium Linker.
+ *
+ * This Linker implementation uses the crazy linker to map and then run Chrome
+ * for Android.
+ *
+ * For more on the operations performed by the Linker, see {@link Linker}.
+ */
+class LegacyLinker extends Linker {
+    // Log tag for this class.
+    private static final String TAG = "cr.library_loader";
+
+    // Name of the library that contains our JNI code.
+    private static final String LINKER_JNI_LIBRARY = "chromium_android_linker";
+
+    // Becomes true after linker initialization.
+    private boolean mInitialized = false;
+
+    // Set to true to indicate that the system supports safe sharing of RELRO sections.
+    private boolean mRelroSharingSupported = false;
+
+    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
+    // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in
+    // the browser process) on low-memory devices.
+    private boolean mInBrowserProcess = true;
+
+    // Becomes true to indicate this process needs to wait for a shared RELRO in
+    // finishLibraryLoad().
+    private boolean mWaitForSharedRelros = false;
+
+    // Becomes true when initialization determines that the browser process can use the
+    // shared RELRO.
+    private boolean mBrowserUsesSharedRelro = false;
+
+    // The map of all RELRO sections either created or used in this process.
+    private Bundle mSharedRelros = null;
+
+    // Current common random base load address.
+    private long mBaseLoadAddress = 0;
+
+    // Current fixed-location load address for the next library called by loadLibrary().
+    private long mCurrentLoadAddress = 0;
+
+    // Becomes true once prepareLibraryLoad() has been called.
+    private boolean mPrepareLibraryLoadCalled = false;
+
+    // The map of libraries that are currently loaded in this process.
+    protected HashMap<String, LibInfo> mLoadedLibraries = null;
+
+    // Used internally to initialize the linker's static data. Assume lock is held.
+    private void ensureInitializedLocked() {
+        assert Thread.holdsLock(mLock);
+
+        if (mInitialized) {
+            return;
+        }
+
+        mRelroSharingSupported = false;
+        if (NativeLibraries.sUseLinker) {
+            if (DEBUG) {
+                Log.i(TAG, "Loading lib" + LINKER_JNI_LIBRARY + ".so");
+            }
+            try {
+                System.loadLibrary(LINKER_JNI_LIBRARY);
+            } catch (UnsatisfiedLinkError e) {
+                // In a component build, the ".cr" suffix is added to each library name.
+                Log.w(TAG, "Couldn't load lib" + LINKER_JNI_LIBRARY + ".so, "
+                                + "trying lib" + LINKER_JNI_LIBRARY + ".cr.so");
+                System.loadLibrary(LINKER_JNI_LIBRARY + ".cr");
+            }
+            mRelroSharingSupported = nativeCanUseSharedRelro();
+            if (!mRelroSharingSupported) {
+                Log.w(TAG, "This system cannot safely share RELRO sections");
+            } else {
+                if (DEBUG) {
+                    Log.i(TAG, "This system supports safe shared RELRO sections");
+                }
+            }
+
+            if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
+                if (SysUtils.isLowEndDevice()) {
+                    mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_LOW;
+                } else {
+                    mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_NORMAL;
+                }
+            }
+
+            switch (BROWSER_SHARED_RELRO_CONFIG) {
+                case BROWSER_SHARED_RELRO_CONFIG_NEVER:
+                    mBrowserUsesSharedRelro = false;
+                    break;
+                case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
+                    if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
+                        mBrowserUsesSharedRelro = true;
+                        Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
+                    } else {
+                        mBrowserUsesSharedRelro = false;
+                    }
+                    break;
+                case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
+                    Log.w(TAG, "Beware: shared RELROs used in all processes!");
+                    mBrowserUsesSharedRelro = true;
+                    break;
+                default:
+                    assert false : "Unreached";
+                    break;
+            }
+        } else {
+            if (DEBUG) {
+                Log.i(TAG, "Linker disabled");
+            }
+        }
+
+        if (!mRelroSharingSupported) {
+            // Sanity.
+            mBrowserUsesSharedRelro = false;
+            mWaitForSharedRelros = false;
+        }
+
+        mInitialized = true;
+    }
+
+    /**
+     * Call this method to determine if this chromium project must
+     * use this linker. If not, System.loadLibrary() should be used to load
+     * libraries instead.
+     */
+    @Override
+    public boolean isUsed() {
+        // Only GYP targets that are APKs and have the 'use_chromium_linker' variable
+        // defined as 1 will use this linker. For all others (the default), the
+        // auto-generated NativeLibraries.sUseLinker variable will be false.
+        if (!NativeLibraries.sUseLinker) return false;
+
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            // At the moment, there is also no point in using this linker if the
+            // system does not support RELRO sharing safely.
+            return mRelroSharingSupported;
+        }
+    }
+
+    /**
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    @Override
+    public boolean isUsingBrowserSharedRelros() {
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            return mBrowserUsesSharedRelro;
+        }
+    }
+
+    /**
+     * Call this method to determine if the chromium project must load
+     * the library directly from the zip file.
+     */
+    @Override
+    public boolean isInZipFile() {
+        return NativeLibraries.sUseLibraryInZipFile;
+    }
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     */
+    @Override
+    public void prepareLibraryLoad() {
+        if (DEBUG) {
+            Log.i(TAG, "prepareLibraryLoad() called");
+        }
+        synchronized (mLock) {
+            mPrepareLibraryLoadCalled = true;
+
+            if (mInBrowserProcess) {
+                // Force generation of random base load address, as well
+                // as creation of shared RELRO sections in this process.
+                setupBaseLoadAddressLocked();
+            }
+        }
+    }
+
+    /**
+     * Call this method just after loading all native shared libraries in this process.
+     * Note that when in a service process, this will block until the RELRO bundle is
+     * received, i.e. when another thread calls useSharedRelros().
+     */
+    @Override
+    public void finishLibraryLoad() {
+        if (DEBUG) {
+            Log.i(TAG, "finishLibraryLoad() called");
+        }
+        synchronized (mLock) {
+            if (DEBUG) {
+                Log.i(TAG,
+                        String.format(Locale.US,
+                                "mInBrowserProcess=%s mBrowserUsesSharedRelro=%s mWaitForSharedRelros=%s",
+                                mInBrowserProcess ? "true" : "false",
+                                mBrowserUsesSharedRelro ? "true" : "false",
+                                mWaitForSharedRelros ? "true" : "false"));
+            }
+
+            if (mLoadedLibraries == null) {
+                if (DEBUG) {
+                    Log.i(TAG, "No libraries loaded");
+                }
+            } else {
+                if (mInBrowserProcess) {
+                    // Create new Bundle containing RELRO section information
+                    // for all loaded libraries. Make it available to getSharedRelros().
+                    mSharedRelros = createBundleFromLibInfoMap(mLoadedLibraries);
+                    if (DEBUG) {
+                        Log.i(TAG, "Shared RELRO created");
+                        dumpBundle(mSharedRelros);
+                    }
+
+                    if (mBrowserUsesSharedRelro) {
+                        useSharedRelrosLocked(mSharedRelros);
+                    }
+                }
+
+                if (mWaitForSharedRelros) {
+                    assert !mInBrowserProcess;
+
+                    // Wait until the shared relro bundle is received from useSharedRelros().
+                    while (mSharedRelros == null) {
+                        try {
+                            mLock.wait();
+                        } catch (InterruptedException ie) {
+                            // no-op
+                        }
+                    }
+                    useSharedRelrosLocked(mSharedRelros);
+                    // Clear the Bundle to ensure its file descriptor references can't be reused.
+                    mSharedRelros.clear();
+                    mSharedRelros = null;
+                }
+            }
+
+            if (NativeLibraries.sEnableLinkerTests && mTestRunnerClassName != null) {
+                // The TestRunner implementation must be instantiated _after_
+                // all libraries are loaded to ensure that its native methods
+                // are properly registered.
+                if (DEBUG) {
+                    Log.i(TAG, "Instantiating " + mTestRunnerClassName);
+                }
+                TestRunner testRunner = null;
+                try {
+                    testRunner = (TestRunner) Class.forName(mTestRunnerClassName).newInstance();
+                } catch (Exception e) {
+                    Log.e(TAG, "Could not extract test runner class name", e);
+                    testRunner = null;
+                }
+                if (testRunner != null) {
+                    if (!testRunner.runChecks(mMemoryDeviceConfig, mInBrowserProcess)) {
+                        Log.wtf(TAG, "Linker runtime tests failed in this process!!");
+                        assert false;
+                    } else {
+                        Log.i(TAG, "All linker tests passed!");
+                    }
+                }
+            }
+        }
+        if (DEBUG) {
+            Log.i(TAG, "finishLibraryLoad() exiting");
+        }
+    }
+
+    /**
+     * Call this to send a Bundle containing the shared RELRO sections to be
+     * used in this process. If initServiceProcess() was previously called,
+     * finishLibraryLoad() will not exit until this method is called in another
+     * thread with a non-null value.
+     * @param bundle The Bundle instance containing a map of shared RELRO sections
+     * to use in this process.
+     */
+    @Override
+    public void useSharedRelros(Bundle bundle) {
+        // Ensure the bundle uses the application's class loader, not the framework
+        // one which doesn't know anything about LibInfo.
+        // Also, hold a fresh copy of it so the caller can't recycle it.
+        Bundle clonedBundle = null;
+        if (bundle != null) {
+            bundle.setClassLoader(LibInfo.class.getClassLoader());
+            clonedBundle = new Bundle(LibInfo.class.getClassLoader());
+            Parcel parcel = Parcel.obtain();
+            bundle.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            clonedBundle.readFromParcel(parcel);
+            parcel.recycle();
+        }
+        if (DEBUG) {
+            Log.i(TAG, "useSharedRelros() called with " + bundle + ", cloned " + clonedBundle);
+        }
+        synchronized (mLock) {
+            // Note that in certain cases, this can be called before
+            // initServiceProcess() in service processes.
+            mSharedRelros = clonedBundle;
+            // Tell any listener blocked in finishLibraryLoad() about it.
+            mLock.notifyAll();
+        }
+    }
+
+    /**
+     * Call this to retrieve the shared RELRO sections created in this process,
+     * after loading all libraries.
+     * @return a new Bundle instance, or null if RELRO sharing is disabled on
+     * this system, or if initServiceProcess() was called previously.
+     */
+    @Override
+    public Bundle getSharedRelros() {
+        if (DEBUG) {
+            Log.i(TAG, "getSharedRelros() called");
+        }
+        synchronized (mLock) {
+            if (!mInBrowserProcess) {
+                if (DEBUG) {
+                    Log.i(TAG, "... returning null Bundle");
+                }
+                return null;
+            }
+
+            // Return the Bundle created in finishLibraryLoad().
+            if (DEBUG) {
+                Log.i(TAG, "... returning " + mSharedRelros);
+            }
+            return mSharedRelros;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    @Override
+    public void disableSharedRelros() {
+        if (DEBUG) {
+            Log.i(TAG, "disableSharedRelros() called");
+        }
+        synchronized (mLock) {
+            mInBrowserProcess = false;
+            mWaitForSharedRelros = false;
+            mBrowserUsesSharedRelro = false;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process is ready to reuse shared RELRO sections from another one.
+     * Typically used when starting service processes.
+     * @param baseLoadAddress the base library load address to use.
+     */
+    @Override
+    public void initServiceProcess(long baseLoadAddress) {
+        if (DEBUG) {
+            Log.i(TAG,
+                    String.format(Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
+        }
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            mInBrowserProcess = false;
+            mBrowserUsesSharedRelro = false;
+            if (mRelroSharingSupported) {
+                mWaitForSharedRelros = true;
+                mBaseLoadAddress = baseLoadAddress;
+                mCurrentLoadAddress = baseLoadAddress;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the base load address of all shared RELRO sections.
+     * This also enforces the creation of shared RELRO sections in
+     * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
+     * @return a common, random base load address, or 0 if RELRO sharing is
+     * disabled.
+     */
+    @Override
+    public long getBaseLoadAddress() {
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            if (!mInBrowserProcess) {
+                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
+                return 0;
+            }
+
+            setupBaseLoadAddressLocked();
+            if (DEBUG) {
+                Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
+                                   mBaseLoadAddress));
+            }
+            return mBaseLoadAddress;
+        }
+    }
+
+    // Used internally to lazily setup the common random base load address.
+    private void setupBaseLoadAddressLocked() {
+        assert Thread.holdsLock(mLock);
+        if (mBaseLoadAddress == 0) {
+            long address = computeRandomBaseLoadAddress();
+            mBaseLoadAddress = address;
+            mCurrentLoadAddress = address;
+            if (address == 0) {
+                // If the computed address is 0, there are issues with finding enough
+                // free address space, so disable RELRO shared / fixed load addresses.
+                Log.w(TAG, "Disabling shared RELROs due address space pressure");
+                mBrowserUsesSharedRelro = false;
+                mWaitForSharedRelros = false;
+            }
+        }
+    }
+
+    /**
+     * Compute a random base load address at which to place loaded libraries.
+     * @return new base load address, or 0 if the system does not support
+     * RELRO sharing.
+     */
+    private long computeRandomBaseLoadAddress() {
+        // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
+        // successfully mapped an area of the given size, on the basis that we will be
+        // able, with high probability, to map our library into it.
+        //
+        // One issue with this is that we do not yet know the size of the library that
+        // we will load is. So here we pass a value that we expect will always be larger
+        // than that needed. If it is smaller the library mapping may still succeed. The
+        // other issue is that although highly unlikely, there is no guarantee that
+        // something else does not map into the area we are going to use between here and
+        // when we try to map into it.
+        //
+        // The above notes mean that all of this is probablistic. It is however okay to do
+        // because if, worst case and unlikely, we get unlucky in our choice of address,
+        // the back-out and retry without the shared RELRO in the ChildProcessService will
+        // keep things running.
+        final long maxExpectedBytes = 192 * 1024 * 1024;
+        final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes);
+        if (DEBUG) {
+            Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address));
+        }
+        return address;
+    }
+
+    // Used for debugging only.
+    private void dumpBundle(Bundle bundle) {
+        if (DEBUG) {
+            Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
+        }
+    }
+
+    /**
+     * Use the shared RELRO section from a Bundle received form another process.
+     * Call this after calling setBaseLoadAddress() then loading all libraries
+     * with loadLibrary().
+     * @param bundle Bundle instance generated with createSharedRelroBundle() in
+     * another process.
+     */
+    private void useSharedRelrosLocked(Bundle bundle) {
+        assert Thread.holdsLock(mLock);
+
+        if (DEBUG) {
+            Log.i(TAG, "Linker.useSharedRelrosLocked() called");
+        }
+
+        if (bundle == null) {
+            if (DEBUG) {
+                Log.i(TAG, "null bundle!");
+            }
+            return;
+        }
+
+        if (!mRelroSharingSupported) {
+            if (DEBUG) {
+                Log.i(TAG, "System does not support RELRO sharing");
+            }
+            return;
+        }
+
+        if (mLoadedLibraries == null) {
+            if (DEBUG) {
+                Log.i(TAG, "No libraries loaded!");
+            }
+            return;
+        }
+
+        if (DEBUG) {
+            dumpBundle(bundle);
+        }
+        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
+
+        // Apply the RELRO section to all libraries that were already loaded.
+        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
+            String libName = entry.getKey();
+            LibInfo libInfo = entry.getValue();
+            if (!nativeUseSharedRelro(libName, libInfo)) {
+                Log.w(TAG, "Could not use shared RELRO section for " + libName);
+            } else {
+                if (DEBUG) {
+                    Log.i(TAG, "Using shared RELRO section for " + libName);
+                }
+            }
+        }
+
+        // In service processes, close all file descriptors from the map now.
+        if (!mInBrowserProcess) closeLibInfoMap(relroMap);
+
+        if (DEBUG) {
+            Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
+        }
+    }
+
+    /**
+     * Load a native shared library with the Chromium linker. If the zip file
+     * is not null, the shared library must be uncompressed and page aligned
+     * inside the zipfile. Note the crazy linker treats libraries and files as
+     * equivalent, so you can only open one library in a given zip file. The
+     * library must not be the Chromium linker library.
+     *
+     * @param zipFilePath The path of the zip file containing the library (or null).
+     * @param libFilePath The path of the library (possibly in the zip file).
+     */
+    @Override
+    public void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
+        if (DEBUG) {
+            Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
+        }
+
+        synchronized (mLock) {
+            ensureInitializedLocked();
+
+            // Security: Ensure prepareLibraryLoad() was called before.
+            // In theory, this can be done lazily here, but it's more consistent
+            // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
+            // that wrap all calls to loadLibrary() in the library loader.
+            assert mPrepareLibraryLoadCalled;
+
+            if (mLoadedLibraries == null) {
+                mLoadedLibraries = new HashMap<String, LibInfo>();
+            }
+
+            if (mLoadedLibraries.containsKey(libFilePath)) {
+                if (DEBUG) {
+                    Log.i(TAG, "Not loading " + libFilePath + " twice");
+                }
+                return;
+            }
+
+            LibInfo libInfo = new LibInfo();
+            long loadAddress = 0;
+            if ((mInBrowserProcess && mBrowserUsesSharedRelro) || mWaitForSharedRelros) {
+                // Load the library at a fixed address.
+                loadAddress = mCurrentLoadAddress;
+            }
+
+            String sharedRelRoName = libFilePath;
+            if (zipFilePath != null) {
+                if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAddress, libInfo)) {
+                    String errorMessage =
+                            "Unable to load library: " + libFilePath + ", in: " + zipFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+                sharedRelRoName = zipFilePath;
+            } else {
+                if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
+                    String errorMessage = "Unable to load library: " + libFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+            }
+
+            // Print the load address to the logcat when testing the linker. The format
+            // of the string is expected by the Python test_runner script as one of:
+            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
+            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
+            // Where <library-name> is the library name, and <address> is the hexadecimal load
+            // address.
+            if (NativeLibraries.sEnableLinkerTests) {
+                Log.i(TAG, String.format(Locale.US, "%s_LIBRARY_ADDRESS: %s %x",
+                                   mInBrowserProcess ? "BROWSER" : "RENDERER", libFilePath,
+                                   libInfo.mLoadAddress));
+            }
+
+            if (mInBrowserProcess) {
+                // Create a new shared RELRO section at the 'current' fixed load address.
+                if (!nativeCreateSharedRelro(sharedRelRoName, mCurrentLoadAddress, libInfo)) {
+                    Log.w(TAG,
+                            String.format(Locale.US, "Could not create shared RELRO for %s at %x",
+                                    libFilePath, mCurrentLoadAddress));
+                } else {
+                    if (DEBUG) {
+                        Log.i(TAG,
+                                String.format(Locale.US, "Created shared RELRO for %s at %x: %s",
+                                        sharedRelRoName, mCurrentLoadAddress, libInfo.toString()));
+                    }
+                }
+            }
+
+            if (mCurrentLoadAddress != 0) {
+                // Compute the next current load address. If mBaseLoadAddress
+                // is not 0, this is an explicit library load address. Otherwise,
+                // this is an explicit load address for relocated RELRO sections
+                // only.
+                mCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
+            }
+
+            mLoadedLibraries.put(sharedRelRoName, libInfo);
+            if (DEBUG) {
+                Log.i(TAG, "Library details " + libInfo.toString());
+            }
+        }
+    }
+
+    /**
+     * Determine whether a library is the linker library. Also deal with the
+     * component build that adds a .cr suffix to the name.
+     */
+    @Override
+    public boolean isChromiumLinkerLibrary(String library) {
+        return library.equals(LINKER_JNI_LIBRARY) || library.equals(LINKER_JNI_LIBRARY + ".cr");
+    }
+
+    /**
+     * Move activity from the native thread to the main UI thread.
+     * Called from native code on its own thread.  Posts a callback from
+     * the UI thread back to native code.
+     *
+     * @param opaque Opaque argument.
+     */
+    @CalledByNative
+    public static void postCallbackOnMainThread(final long opaque) {
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                nativeRunCallbackOnUiThread(opaque);
+            }
+        });
+    }
+
+    /**
+     * Native method to run callbacks on the main UI thread.
+     * Supplied by the crazy linker and called by postCallbackOnMainThread.
+     * @param opaque Opaque crazy linker arguments.
+     */
+    private static native void nativeRunCallbackOnUiThread(long opaque);
+
+    /**
+     * Native method used to load a library.
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibrary(
+            String library, long loadAddress, LibInfo libInfo);
+
+    /**
+     * Native method used to load a library which is inside a zipfile.
+     * @param zipfileName Filename of the zip file containing the library.
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibraryInZipFile(
+            String zipfileName, String libraryName, long loadAddress, LibInfo libInfo);
+
+    /**
+     * Native method used to create a shared RELRO section.
+     * If the library was already loaded at the same address using
+     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
+     * this loads a new temporary library at the specified address,
+     * creates and extracts the RELRO section from it, then unloads it.
+     * @param library Library name.
+     * @param loadAddress load address, which can be different from the one
+     * used to load the library in the current process!
+     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
+     * and mRelroFd will be set.
+     * @return true on success, false otherwise.
+     */
+    private static native boolean nativeCreateSharedRelro(
+            String library, long loadAddress, LibInfo libInfo);
+
+    /**
+     * Native method used to use a shared RELRO section.
+     * @param library Library name.
+     * @param libInfo A LibInfo instance containing valid RELRO information
+     * @return true on success.
+     */
+    private static native boolean nativeUseSharedRelro(String library, LibInfo libInfo);
+
+    /**
+     * Checks that the system supports shared RELROs. Old Android kernels
+     * have a bug in the way they check Ashmem region protection flags, which
+     * makes using shared RELROs unsafe. This method performs a simple runtime
+     * check for this misfeature, even though nativeEnableSharedRelro() will
+     * always fail if this returns false.
+     */
+    private static native boolean nativeCanUseSharedRelro();
+
+    /**
+     * Return a random address that should be free to be mapped with the given size.
+     * Maps an area of size bytes, and if successful then unmaps it and returns
+     * the address of the area allocated by the system (with ASLR). The idea is
+     * that this area should remain free of other mappings until we map our library
+     * into it.
+     * @param sizeBytes Size of area in bytes to search for.
+     * @return address to pass to future mmap, or 0 on error.
+     */
+    private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index a789eff..5dfc2ba 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -11,16 +11,17 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.SystemClock;
-import android.util.Log;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.CommandLine;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 import org.chromium.base.PackageUtils;
 import org.chromium.base.TraceEvent;
-import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import javax.annotation.Nullable;
 
 /**
@@ -39,7 +40,7 @@
  */
 @JNINamespace("base::android")
 public class LibraryLoader {
-    private static final String TAG = "LibraryLoader";
+    private static final String TAG = "cr.library_loader";
 
     // Set to true to enable debug logs.
     private static final boolean DEBUG = false;
@@ -73,15 +74,19 @@
     // APK file directly.
     private boolean mLibraryWasLoadedFromApk;
 
-    // One-way switch becomes false if the Chromium library should be loaded
-    // directly from the APK file but it was compressed or not aligned.
-    private boolean mLibraryIsMappableInApk = true;
-
     // The type of process the shared library is loaded in.
     // This member can be accessed from multiple threads simultaneously, so it have to be
     // final (like now) or be protected in some way (volatile of synchronized).
     private final int mLibraryProcessType;
 
+    // One-way switch that becomes true once
+    // {@link asyncPrefetchLibrariesToMemory} has been called.
+    private final AtomicBoolean mPrefetchLibraryHasBeenCalled;
+
+    // The number of milliseconds it took to load all the native libraries, which
+    // will be reported via UMA. Set once when the libraries are done loading.
+    private long mLibraryLoadTimeMs;
+
     /**
      * @param libraryProcessType the process the shared library is loaded in. refer to
      *                           LibraryProcessType for possible values.
@@ -101,38 +106,21 @@
 
     private LibraryLoader(int libraryProcessType) {
         mLibraryProcessType = libraryProcessType;
-    }
-
-    /**
-     * The same as ensureInitialized(null, false), should only be called
-     * by non-browser processes.
-     *
-     * @throws ProcessInitException
-     */
-    @VisibleForTesting
-    public void ensureInitialized() throws ProcessInitException {
-        ensureInitialized(null, false);
+        mPrefetchLibraryHasBeenCalled = new AtomicBoolean();
     }
 
     /**
      *  This method blocks until the library is fully loaded and initialized.
      *
-     *  @param context The context in which the method is called, the caller
-     *    may pass in a null context if it doesn't know in which context it
-     *    is running.
-     *
-     *  @param shouldDeleteFallbackLibraries The flag tells whether the method
-     *    should delete the fallback libraries or not.
+     *  @param context The context in which the method is called.
      */
-    public void ensureInitialized(
-            Context context, boolean shouldDeleteFallbackLibraries)
-            throws ProcessInitException {
+    public void ensureInitialized(Context context) throws ProcessInitException {
         synchronized (sLock) {
             if (mInitialized) {
                 // Already initialized, nothing to do.
                 return;
             }
-            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+            loadAlreadyLocked(context);
             initializeAlreadyLocked();
         }
     }
@@ -145,32 +133,19 @@
     }
 
     /**
-     * The same as loadNow(null, false), should only be called by
-     * non-browser process.
-     *
-     * @throws ProcessInitException
-     */
-    public void loadNow() throws ProcessInitException {
-        loadNow(null, false);
-    }
-
-    /**
      * Loads the library and blocks until the load completes. The caller is responsible
      * for subsequently calling ensureInitialized().
      * May be called on any thread, but should only be called once. Note the thread
      * this is called on will be the thread that runs the native code's static initializers.
      * See the comment in doInBackground() for more considerations on this.
      *
-     * @param context The context the code is running, or null if it doesn't have one.
-     * @param shouldDeleteFallbackLibraries The flag tells whether the method
-     *   should delete the old fallback libraries or not.
+     * @param context The context the code is running.
      *
      * @throws ProcessInitException if the native library failed to load.
      */
-    public void loadNow(Context context, boolean shouldDeleteFallbackLibraries)
-            throws ProcessInitException {
+    public void loadNow(Context context) throws ProcessInitException {
         synchronized (sLock) {
-            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+            loadAlreadyLocked(context);
         }
     }
 
@@ -193,10 +168,9 @@
      *
      * This is done this way, as testing shows that fadvise(FADV_WILLNEED) is
      * detrimental to the startup time.
-     *
-     * @param context the application context.
      */
-    public void asyncPrefetchLibrariesToMemory(final Context context) {
+    public void asyncPrefetchLibrariesToMemory() {
+        if (!mPrefetchLibraryHasBeenCalled.compareAndSet(false, true)) return;
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
@@ -213,34 +187,26 @@
     }
 
     // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
-    private void loadAlreadyLocked(
-            Context context, boolean shouldDeleteFallbackLibraries)
-            throws ProcessInitException {
+    private void loadAlreadyLocked(Context context) throws ProcessInitException {
         try {
             if (!mLoaded) {
                 assert !mInitialized;
 
                 long startTime = SystemClock.uptimeMillis();
-                boolean useChromiumLinker = Linker.isUsed();
-                boolean fallbackWasUsed = false;
+                Linker linker = Linker.getInstance();
+                boolean useChromiumLinker = linker.isUsed();
 
                 if (useChromiumLinker) {
                     // Determine the APK file path.
-                    String apkFilePath = null;
-                    if (context != null) {
-                        apkFilePath = getLibraryApkPath(context);
-                    } else {
-                        Log.w(TAG, "could not check load from APK support due to null context");
-                    }
-
+                    String apkFilePath = getLibraryApkPath(context);
                     // Load libraries using the Chromium linker.
-                    Linker.prepareLibraryLoad();
+                    linker.prepareLibraryLoad();
 
                     for (String library : NativeLibraries.LIBRARIES) {
                         // Don't self-load the linker. This is because the build system is
                         // not clever enough to understand that all the libraries packaged
                         // in the final .apk don't need to be explicitly loaded.
-                        if (Linker.isChromiumLinkerLibrary(library)) {
+                        if (linker.isChromiumLinkerLibrary(library)) {
                             if (DEBUG) Log.i(TAG, "ignoring self-linker load");
                             continue;
                         }
@@ -248,26 +214,11 @@
                         // Determine where the library should be loaded from.
                         String zipFilePath = null;
                         String libFilePath = System.mapLibraryName(library);
-                        if (apkFilePath != null && Linker.isInZipFile()) {
-                            // The library is in the APK file.
-                            if (!Linker.checkLibraryIsMappableInApk(apkFilePath, libFilePath)) {
-                                mLibraryIsMappableInApk = false;
-                            }
-                            if (mLibraryIsMappableInApk) {
-                                // Load directly from the APK.
-                                zipFilePath = apkFilePath;
-                                Log.i(TAG, "Loading " + library + " directly from within "
-                                        + apkFilePath);
-                            } else {
-                                // Unpack library fallback.
-                                Log.i(TAG, "Loading " + library
-                                        + " using unpack library fallback from within "
-                                        + apkFilePath);
-                                libFilePath = LibraryLoaderHelper.buildFallbackLibrary(
-                                        context, library);
-                                fallbackWasUsed = true;
-                                Log.i(TAG, "Built fallback library " + libFilePath);
-                            }
+                        if (linker.isInZipFile()) {
+                            // Load directly from the APK.
+                            zipFilePath = apkFilePath;
+                            Log.i(TAG,
+                                    "Loading " + library + " directly from within " + apkFilePath);
                         } else {
                             // The library is in its own file.
                             Log.i(TAG, "Loading " + library);
@@ -275,7 +226,7 @@
 
                         // Load the library.
                         boolean isLoaded = false;
-                        if (Linker.isUsingBrowserSharedRelros()) {
+                        if (linker.isUsingBrowserSharedRelros()) {
                             mIsUsingBrowserSharedRelros = true;
                             try {
                                 loadLibrary(zipFilePath, libFilePath);
@@ -283,7 +234,7 @@
                             } catch (UnsatisfiedLinkError e) {
                                 Log.w(TAG, "Failed to load native library with shared RELRO, "
                                         + "retrying without");
-                                Linker.disableSharedRelros();
+                                linker.disableSharedRelros();
                                 mLoadAtFixedAddressFailed = true;
                             }
                         }
@@ -292,7 +243,7 @@
                         }
                     }
 
-                    Linker.finishLibraryLoad();
+                    linker.finishLibraryLoad();
                 } else {
                     // Load libraries using the system linker.
                     for (String library : NativeLibraries.LIBRARIES) {
@@ -300,17 +251,10 @@
                     }
                 }
 
-                if (!fallbackWasUsed && context != null
-                        && shouldDeleteFallbackLibraries) {
-                    LibraryLoaderHelper.deleteLibrariesAsynchronously(
-                            context, LibraryLoaderHelper.LOAD_FROM_APK_FALLBACK_DIR);
-                }
-
                 long stopTime = SystemClock.uptimeMillis();
+                mLibraryLoadTimeMs = stopTime - startTime;
                 Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
-                        stopTime - startTime,
-                        startTime % 10000,
-                        stopTime % 10000));
+                                   mLibraryLoadTimeMs, startTime % 10000, stopTime % 10000));
 
                 mLoaded = true;
             }
@@ -318,11 +262,9 @@
             throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED, e);
         }
         // Check that the version of the library we have loaded matches the version we expect
-        Log.i(TAG, String.format(
-                "Expected native library version number \"%s\","
-                        + "actual native library version number \"%s\"",
-                NativeLibraries.sVersionNumber,
-                nativeGetVersionNumber()));
+        Log.i(TAG, String.format("Expected native library version number \"%s\", "
+                                   + "actual native library version number \"%s\"",
+                           NativeLibraries.sVersionNumber, nativeGetVersionNumber()));
         if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) {
             throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION);
         }
@@ -356,7 +298,7 @@
     // Load a native shared library with the Chromium linker. If the zip file
     // path is not null, the library is loaded directly from the zip file.
     private void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
-        Linker.loadLibrary(zipFilePath, libFilePath);
+        Linker.getInstance().loadLibrary(zipFilePath, libFilePath);
         if (zipFilePath != null) {
             mLibraryWasLoadedFromApk = true;
         }
@@ -426,26 +368,22 @@
     // Record Chromium linker histogram state for the main browser process. Called from
     // onNativeInitializationComplete().
     private void recordBrowserProcessHistogram(Context context) {
-        if (Linker.isUsed()) {
+        if (Linker.getInstance().isUsed()) {
             nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros,
-                                                              mLoadAtFixedAddressFailed,
-                                                              getLibraryLoadFromApkStatus(context));
+                    mLoadAtFixedAddressFailed, getLibraryLoadFromApkStatus(context),
+                    mLibraryLoadTimeMs);
         }
     }
 
     // Returns the device's status for loading a library directly from the APK file.
     // This method can only be called when the Chromium linker is used.
     private int getLibraryLoadFromApkStatus(Context context) {
-        assert Linker.isUsed();
+        assert Linker.getInstance().isUsed();
 
         if (mLibraryWasLoadedFromApk) {
             return LibraryLoadFromApkStatusCodes.SUCCESSFUL;
         }
 
-        if (!mLibraryIsMappableInApk) {
-            return LibraryLoadFromApkStatusCodes.USED_UNPACK_LIBRARY_FALLBACK;
-        }
-
         // There were no libraries to be loaded directly from the APK file.
         return LibraryLoadFromApkStatusCodes.UNKNOWN;
     }
@@ -456,9 +394,9 @@
     // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly.
     public void registerRendererProcessHistogram(boolean requestedSharedRelro,
                                                  boolean loadAtFixedAddressFailed) {
-        if (Linker.isUsed()) {
-            nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedSharedRelro,
-                                                                 loadAtFixedAddressFailed);
+        if (Linker.getInstance().isUsed()) {
+            nativeRegisterChromiumAndroidLinkerRendererHistogram(
+                    requestedSharedRelro, loadAtFixedAddressFailed, mLibraryLoadTimeMs);
         }
     }
 
@@ -485,18 +423,18 @@
     // Method called to record statistics about the Chromium linker operation for the main
     // browser process. Indicates whether the linker attempted relro sharing for the browser,
     // and if it did, whether the library failed to load at a fixed address. Also records
-    // support for loading a library directly from the APK file.
+    // support for loading a library directly from the APK file, and the number of milliseconds
+    // it took to load the libraries.
     private native void nativeRecordChromiumAndroidLinkerBrowserHistogram(
-            boolean isUsingBrowserSharedRelros,
-            boolean loadAtFixedAddressFailed,
-            int libraryLoadFromApkStatus);
+            boolean isUsingBrowserSharedRelros, boolean loadAtFixedAddressFailed,
+            int libraryLoadFromApkStatus, long libraryLoadTime);
 
     // Method called to register (for later recording) statistics about the Chromium linker
     // operation for a renderer process. Indicates whether the linker attempted relro sharing,
-    // and if it did, whether the library failed to load at a fixed address.
+    // and if it did, whether the library failed to load at a fixed address. Also records the
+    // number of milliseconds it took to load the libraries.
     private native void nativeRegisterChromiumAndroidLinkerRendererHistogram(
-            boolean requestedSharedRelro,
-            boolean loadAtFixedAddressFailed);
+            boolean requestedSharedRelro, boolean loadAtFixedAddressFailed, long libraryLoadTime);
 
     // Get the version of the native library. This is needed so that we can check we
     // have the right version before initializing the (rest of the) JNI.
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
deleted file mode 100644
index 7dd1a29..0000000
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-package org.chromium.base.library_loader;
-
-import android.content.Context;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
-
-/**
- * Class representing an exception which occured during the unpacking process.
- */
-class UnpackingException extends Exception {
-    public UnpackingException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public UnpackingException(String message) {
-        super(message);
-    }
-}
-
-/**
- * The class provides helper functions to extract native libraries from APK,
- * and load libraries from there.
- */
-class LibraryLoaderHelper {
-    private static final String TAG = "LibraryLoaderHelper";
-
-    // Fallback directories.
-    static final String LOAD_FROM_APK_FALLBACK_DIR = "fallback";
-
-    private static final int BUFFER_SIZE = 16384;
-
-    /**
-     * Returns the directory for holding extracted native libraries.
-     * It may create the directory if it doesn't exist.
-     *
-     * @param context The context the code is running.
-     * @param dirName The name of the directory containing the libraries.
-     * @return The directory file object.
-     */
-    static File getLibDir(Context context, String dirName) {
-        return context.getDir(dirName, Context.MODE_PRIVATE);
-    }
-
-    /**
-     * Delete libraries and their directory synchronously.
-     */
-    private static void deleteLibrariesSynchronously(Context context, String dirName) {
-        File libDir = getLibDir(context, dirName);
-        deleteObsoleteLibraries(libDir, Collections.<File>emptyList());
-    }
-
-    /**
-     * Delete libraries and their directory asynchronously.
-     * The actual deletion is done in a background thread.
-     */
-    static void deleteLibrariesAsynchronously(
-            final Context context, final String dirName) {
-        // Child process should not reach here.
-        new Thread() {
-            @Override
-            public void run() {
-                deleteLibrariesSynchronously(context, dirName);
-            }
-        }.start();
-    }
-
-    /**
-     * Copy a library from a zip file to the application's private directory.
-     * This is used as a fallback when we are unable to load the library
-     * directly from the APK file (crbug.com/390618).
-     *
-     * @param context The context the code is running in.
-     * @param library Library name.
-     * @return name of the fallback copy of the library.
-     */
-    static String buildFallbackLibrary(Context context, String library) {
-        try {
-            String libName = System.mapLibraryName(library);
-            File fallbackLibDir = getLibDir(context, LOAD_FROM_APK_FALLBACK_DIR);
-            File fallbackLibFile = new File(fallbackLibDir, libName);
-            String pathInZipFile = Linker.getLibraryFilePathInZipFile(libName);
-            Map<String, File> dstFiles = Collections.singletonMap(pathInZipFile, fallbackLibFile);
-
-            deleteObsoleteLibraries(fallbackLibDir, dstFiles.values());
-            unpackLibraries(context, dstFiles);
-
-            return fallbackLibFile.getAbsolutePath();
-        } catch (Exception e) {
-            String errorMessage = "Unable to load fallback for library " + library
-                    + " (" + (e.getMessage() == null ? e.toString() : e.getMessage()) + ")";
-            Log.e(TAG, errorMessage, e);
-            throw new UnsatisfiedLinkError(errorMessage);
-        }
-    }
-
-    // Delete obsolete libraries from a library folder.
-    private static void deleteObsoleteLibraries(File libDir, Collection<File> keptFiles) {
-        try {
-            // Build a list of libraries that should NOT be deleted.
-            Set<String> keptFileNames = new HashSet<String>();
-            for (File k : keptFiles) {
-                keptFileNames.add(k.getName());
-            }
-
-            // Delete the obsolete libraries.
-            Log.i(TAG, "Deleting obsolete libraries in " + libDir.getPath());
-            File[] files = libDir.listFiles();
-            if (files != null) {
-                for (File f : files) {
-                    if (!keptFileNames.contains(f.getName())) {
-                        delete(f);
-                    }
-                }
-            } else {
-                Log.e(TAG, "Failed to list files in " + libDir.getPath());
-            }
-
-            // Delete the folder if no libraries were kept.
-            if (keptFileNames.isEmpty()) {
-                delete(libDir);
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to remove obsolete libraries from " + libDir.getPath());
-        }
-    }
-
-    // Unpack libraries from a zip file to the file system.
-    private static void unpackLibraries(Context context,
-            Map<String, File> dstFiles) throws UnpackingException {
-        String zipFilePath = context.getApplicationInfo().sourceDir;
-        Log.i(TAG, "Opening zip file " + zipFilePath);
-        File zipFile = new File(zipFilePath);
-        ZipFile zipArchive = openZipFile(zipFile);
-
-        try {
-            for (Entry<String, File> d : dstFiles.entrySet()) {
-                String pathInZipFile = d.getKey();
-                File dstFile = d.getValue();
-                Log.i(TAG, "Unpacking " + pathInZipFile
-                        + " to " + dstFile.getAbsolutePath());
-                ZipEntry packedLib = zipArchive.getEntry(pathInZipFile);
-
-                if (needToUnpackLibrary(zipFile, packedLib, dstFile)) {
-                    unpackLibraryFromZipFile(zipArchive, packedLib, dstFile);
-                    setLibraryFilePermissions(dstFile);
-                }
-            }
-        } finally {
-            closeZipFile(zipArchive);
-        }
-    }
-
-    // Open a zip file.
-    private static ZipFile openZipFile(File zipFile) throws UnpackingException {
-        try {
-            return new ZipFile(zipFile);
-        } catch (ZipException e) {
-            throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
-        } catch (IOException e) {
-            throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
-        }
-    }
-
-    // Determine whether it is necessary to unpack a library from a zip file.
-    private static boolean needToUnpackLibrary(
-            File zipFile, ZipEntry packedLib, File dstFile) {
-        // Check if the fallback library already exists.
-        if (!dstFile.exists()) {
-            Log.i(TAG, "File " + dstFile.getPath() + " does not exist yet");
-            return true;
-        }
-
-        // Check last modification dates.
-        long zipTime = zipFile.lastModified();
-        long fallbackLibTime = dstFile.lastModified();
-        if (zipTime > fallbackLibTime) {
-            Log.i(TAG, "Not using existing fallback file because "
-                    + "the APK file " + zipFile.getPath()
-                    + " (timestamp=" + zipTime + ") is newer than "
-                    + "the fallback library " + dstFile.getPath()
-                    + "(timestamp=" + fallbackLibTime + ")");
-            return true;
-        }
-
-        // Check file sizes.
-        long packedLibSize = packedLib.getSize();
-        long fallbackLibSize = dstFile.length();
-        if (fallbackLibSize != packedLibSize) {
-            Log.i(TAG, "Not using existing fallback file because "
-                    + "the library in the APK " + zipFile.getPath()
-                    + " (" + packedLibSize + "B) has a different size than "
-                    + "the fallback library " + dstFile.getPath()
-                    + "(" + fallbackLibSize + "B)");
-            return true;
-        }
-
-        Log.i(TAG, "Reusing existing file " + dstFile.getPath());
-        return false;
-    }
-
-    // Unpack a library from a zip file to the filesystem.
-    private static void unpackLibraryFromZipFile(ZipFile zipArchive, ZipEntry packedLib,
-            File dstFile) throws UnpackingException {
-        // Open input stream for the library file inside the zip file.
-        InputStream in;
-        try {
-            in = zipArchive.getInputStream(packedLib);
-        } catch (IOException e) {
-            throw new UnpackingException(
-                    "IO exception when locating library in the zip file", e);
-        }
-
-        // Ensure that the input stream is closed at the end.
-        try {
-            // Delete existing file if it exists.
-            if (dstFile.exists()) {
-                Log.i(TAG, "Deleting existing unpacked library file " + dstFile.getPath());
-                if (!dstFile.delete()) {
-                    throw new UnpackingException(
-                            "Failed to delete existing unpacked library file " + dstFile.getPath());
-                }
-            }
-
-            // Ensure that the library folder exists. Since this is added
-            // for increased robustness, we log errors and carry on.
-            try {
-                dstFile.getParentFile().mkdirs();
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to make library folder", e);
-            }
-
-            // Create the destination file.
-            try {
-                if (!dstFile.createNewFile()) {
-                    throw new UnpackingException("existing unpacked library file was not deleted");
-                }
-            } catch (IOException e) {
-                throw new UnpackingException("failed to create unpacked library file", e);
-            }
-
-            // Open the output stream for the destination file.
-            OutputStream out;
-            try {
-                out = new BufferedOutputStream(new FileOutputStream(dstFile));
-            } catch (FileNotFoundException e) {
-                throw new UnpackingException(
-                        "failed to open output stream for unpacked library file", e);
-            }
-
-            // Ensure that the output stream is closed at the end.
-            try {
-                // Copy the library from the zip file to the destination file.
-                Log.i(TAG, "Copying " + packedLib.getName() + " from " + zipArchive.getName()
-                        + " to " + dstFile.getPath());
-                byte[] buffer = new byte[BUFFER_SIZE];
-                int len;
-                while ((len = in.read(buffer)) != -1) {
-                    out.write(buffer, 0, len);
-                }
-            } catch (IOException e) {
-                throw new UnpackingException(
-                        "failed to copy the library from the zip file", e);
-            } finally {
-                close(out, "output stream");
-            }
-        } finally {
-            close(in, "input stream");
-        }
-    }
-
-    // Set up library file permissions.
-    private static void setLibraryFilePermissions(File libFile) {
-        // Change permission to rwxr-xr-x
-        Log.i(TAG, "Setting file permissions for " + libFile.getPath());
-        if (!libFile.setReadable(/* readable */ true, /* ownerOnly */ false)) {
-            Log.e(TAG, "failed to chmod a+r the temporary file");
-        }
-        if (!libFile.setExecutable(/* executable */ true, /* ownerOnly */ false)) {
-            Log.e(TAG, "failed to chmod a+x the temporary file");
-        }
-        if (!libFile.setWritable(/* writable */ true)) {
-            Log.e(TAG, "failed to chmod +w the temporary file");
-        }
-    }
-
-    // Close a closable and log a warning if it fails.
-    private static void close(Closeable closeable, String name) {
-        try {
-            closeable.close();
-        } catch (IOException e) {
-            // Warn and ignore.
-            Log.w(TAG, "IO exception when closing " + name, e);
-        }
-    }
-
-    // Close a zip file and log a warning if it fails.
-    // This needs to be a separate method because ZipFile is not Closeable in
-    // Java 6 (used on some older devices).
-    private static void closeZipFile(ZipFile file) {
-        try {
-            file.close();
-        } catch (IOException e) {
-            // Warn and ignore.
-            Log.w(TAG, "IO exception when closing zip file", e);
-        }
-    }
-
-    // Delete a file and log it.
-    private static void delete(File file) {
-        if (file.delete()) {
-            Log.i(TAG, "Deleted " + file.getPath());
-        } else {
-            Log.w(TAG, "Failed to delete " + file.getPath());
-        }
-    }
-}
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
index 9a64a3f..c769339 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -8,14 +8,10 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
-import android.util.Log;
 
-import org.chromium.base.CalledByNative;
-import org.chromium.base.SysUtils;
-import org.chromium.base.ThreadUtils;
+import org.chromium.base.Log;
 import org.chromium.base.annotations.AccessedByNative;
 
-import java.io.FileNotFoundException;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
@@ -153,13 +149,19 @@
  *
  *    This method also ensures the process uses the shared RELROs.
  */
-public class Linker {
-
-    // Log tag for this class. This must match the name of the linker's native library.
-    private static final String TAG = "chromium_android_linker";
+public abstract class Linker {
+    // Log tag for this class.
+    private static final String TAG = "cr.library_loader";
 
     // Set to true to enable debug logs.
-    private static final boolean DEBUG = false;
+    protected static final boolean DEBUG = false;
+
+    // Used to pass the shared RELRO Bundle through Binder.
+    public static final String EXTRA_LINKER_SHARED_RELROS =
+            "org.chromium.base.android.linker.shared_relros";
+
+    // Guards all access to the linker.
+    protected final Object mLock = new Object();
 
     // Constants used to control the behaviour of the browser process with
     // regards to the shared RELRO section.
@@ -188,96 +190,24 @@
     // Indicates if this is a low-memory device or not. The default is to
     // determine this by probing the system at runtime, but this can be forced
     // for testing by calling setMemoryDeviceConfig().
-    private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
+    protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
 
-    // Becomes true after linker initialization.
-    private static boolean sInitialized = false;
+    // Singleton.
+    private static Linker sSingleton = null;
+    private static Object sSingletonLock = new Object();
 
-    // Set to true to indicate that the system supports safe sharing of RELRO sections.
-    private static boolean sRelroSharingSupported = false;
+    // Protected singleton constructor.
+    protected Linker() {}
 
-    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
-    // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in
-    // the browser process) on low-memory devices.
-    private static boolean sInBrowserProcess = true;
-
-    // Becomes true to indicate this process needs to wait for a shared RELRO in
-    // finishLibraryLoad().
-    private static boolean sWaitForSharedRelros = false;
-
-    // Becomes true when initialization determines that the browser process can use the
-    // shared RELRO.
-    private static boolean sBrowserUsesSharedRelro = false;
-
-    // The map of all RELRO sections either created or used in this process.
-    private static Bundle sSharedRelros = null;
-
-    // Current common random base load address.
-    private static long sBaseLoadAddress = 0;
-
-    // Current fixed-location load address for the next library called by loadLibrary().
-    private static long sCurrentLoadAddress = 0;
-
-    // Becomes true once prepareLibraryLoad() has been called.
-    private static boolean sPrepareLibraryLoadCalled = false;
-
-    // Used internally to initialize the linker's static data. Assume lock is held.
-    private static void ensureInitializedLocked() {
-        assert Thread.holdsLock(Linker.class);
-
-        if (!sInitialized) {
-            sRelroSharingSupported = false;
-            if (NativeLibraries.sUseLinker) {
-                if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so");
-                try {
-                    System.loadLibrary(TAG);
-                } catch (UnsatisfiedLinkError  e) {
-                    // In a component build, the ".cr" suffix is added to each library name.
-                    Log.w(TAG, "Couldn't load lib" + TAG + ".so, trying lib" + TAG + ".cr.so");
-                    System.loadLibrary(TAG + ".cr");
-                }
-                sRelroSharingSupported = nativeCanUseSharedRelro();
-                if (!sRelroSharingSupported) {
-                    Log.w(TAG, "This system cannot safely share RELRO sections");
-                } else {
-                    if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
-                }
-
-                if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
-                    sMemoryDeviceConfig = SysUtils.isLowEndDevice()
-                            ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
-                }
-
-                switch (BROWSER_SHARED_RELRO_CONFIG) {
-                    case BROWSER_SHARED_RELRO_CONFIG_NEVER:
-                        sBrowserUsesSharedRelro = false;
-                        break;
-                    case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
-                        sBrowserUsesSharedRelro =
-                                (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW);
-                        if (sBrowserUsesSharedRelro) {
-                            Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
-                        }
-                        break;
-                    case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
-                        Log.w(TAG, "Beware: shared RELROs used in all processes!");
-                        sBrowserUsesSharedRelro = true;
-                        break;
-                    default:
-                        assert false : "Unreached";
-                        break;
-                }
-            } else {
-                if (DEBUG) Log.i(TAG, "Linker disabled");
+    // Get singleton instance.
+    public static final Linker getInstance() {
+        synchronized (sSingletonLock) {
+            if (sSingleton == null) {
+                // TODO(simonb): Extend later to return either a LegacyLinker
+                // or a ModernLinker instance.
+                sSingleton = new LegacyLinker();
             }
-
-            if (!sRelroSharingSupported) {
-                // Sanity.
-                sBrowserUsesSharedRelro = false;
-                sWaitForSharedRelros = false;
-            }
-
-            sInitialized = true;
+            return sSingleton;
         }
     }
 
@@ -297,7 +227,7 @@
     }
 
     // The name of a class that implements TestRunner.
-    static String sTestRunnerClassName = null;
+    String mTestRunnerClassName = null;
 
     /**
      * Set the TestRunner by its class name. It will be instantiated at
@@ -305,17 +235,18 @@
      * @param testRunnerClassName null or a String for the class name of the
      * TestRunner to use.
      */
-    public static void setTestRunnerClassName(String testRunnerClassName) {
-        if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
-
+    public void setTestRunnerClassName(String testRunnerClassName) {
+        if (DEBUG) {
+            Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
+        }
         if (!NativeLibraries.sEnableLinkerTests) {
-            // Ignore this in production code to prevent malvolent runtime injection.
+            // Ignore this in production code to prevent malevolent runtime injection.
             return;
         }
 
-        synchronized (Linker.class) {
-            assert sTestRunnerClassName == null;
-            sTestRunnerClassName = testRunnerClassName;
+        synchronized (mLock) {
+            assert mTestRunnerClassName == null;
+            mTestRunnerClassName = testRunnerClassName;
         }
     }
 
@@ -326,9 +257,9 @@
      * @return null or a String holding the name of the class implementing
      * the TestRunner set by calling setTestRunnerClassName() previously.
      */
-    public static String getTestRunnerClassName() {
-        synchronized (Linker.class) {
-            return sTestRunnerClassName;
+    public String getTestRunnerClassName() {
+        synchronized (mLock) {
+            return mTestRunnerClassName;
         }
     }
 
@@ -337,12 +268,14 @@
      * memory device configuration. Should only be used for testing.
      * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
      */
-    public static void setMemoryDeviceConfig(int memoryDeviceConfig) {
-        if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
+    public void setMemoryDeviceConfig(int memoryDeviceConfig) {
+        if (DEBUG) {
+            Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
+        }
         // Sanity check. This method should only be called during tests.
         assert NativeLibraries.sEnableLinkerTests;
-        synchronized (Linker.class) {
-            assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
+        synchronized (mLock) {
+            assert mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
             assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
                    || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
             if (DEBUG) {
@@ -352,7 +285,7 @@
                     Log.i(TAG, "Simulating a regular-memory device");
                 }
             }
-            sMemoryDeviceConfig = memoryDeviceConfig;
+            mMemoryDeviceConfig = memoryDeviceConfig;
         }
     }
 
@@ -361,130 +294,31 @@
      * use this linker. If not, System.loadLibrary() should be used to load
      * libraries instead.
      */
-    public static boolean isUsed() {
-        // Only GYP targets that are APKs and have the 'use_chromium_linker' variable
-        // defined as 1 will use this linker. For all others (the default), the
-        // auto-generated NativeLibraries.sUseLinker variable will be false.
-        if (!NativeLibraries.sUseLinker) return false;
-
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-            // At the moment, there is also no point in using this linker if the
-            // system does not support RELRO sharing safely.
-            return sRelroSharingSupported;
-        }
-    }
+    public abstract boolean isUsed();
 
     /**
      * Call this method to determine if the linker will try to use shared RELROs
      * for the browser process.
      */
-    public static boolean isUsingBrowserSharedRelros() {
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-            return sBrowserUsesSharedRelro;
-        }
-    }
+    public abstract boolean isUsingBrowserSharedRelros();
 
     /**
      * Call this method to determine if the chromium project must load
      * the library directly from the zip file.
      */
-    public static boolean isInZipFile() {
-        return NativeLibraries.sUseLibraryInZipFile;
-    }
+    public abstract boolean isInZipFile();
 
     /**
      * Call this method just before loading any native shared libraries in this process.
      */
-    public static void prepareLibraryLoad() {
-        if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
-        synchronized (Linker.class) {
-            sPrepareLibraryLoadCalled = true;
-
-            if (sInBrowserProcess) {
-                // Force generation of random base load address, as well
-                // as creation of shared RELRO sections in this process.
-                setupBaseLoadAddressLocked();
-            }
-        }
-    }
+    public abstract void prepareLibraryLoad();
 
     /**
      * Call this method just after loading all native shared libraries in this process.
      * Note that when in a service process, this will block until the RELRO bundle is
      * received, i.e. when another thread calls useSharedRelros().
      */
-    public static void finishLibraryLoad() {
-        if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
-        synchronized (Linker.class) {
-            if (DEBUG) Log.i(TAG, String.format(
-                    Locale.US,
-                    "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSharedRelros=%s",
-                    sInBrowserProcess ? "true" : "false",
-                    sBrowserUsesSharedRelro ? "true" : "false",
-                    sWaitForSharedRelros ? "true" : "false"));
-
-            if (sLoadedLibraries == null) {
-                if (DEBUG) Log.i(TAG, "No libraries loaded");
-            } else {
-                if (sInBrowserProcess) {
-                    // Create new Bundle containing RELRO section information
-                    // for all loaded libraries. Make it available to getSharedRelros().
-                    sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries);
-                    if (DEBUG) {
-                        Log.i(TAG, "Shared RELRO created");
-                        dumpBundle(sSharedRelros);
-                    }
-
-                    if (sBrowserUsesSharedRelro) {
-                        useSharedRelrosLocked(sSharedRelros);
-                    }
-                }
-
-                if (sWaitForSharedRelros) {
-                    assert !sInBrowserProcess;
-
-                    // Wait until the shared relro bundle is received from useSharedRelros().
-                    while (sSharedRelros == null) {
-                        try {
-                            Linker.class.wait();
-                        } catch (InterruptedException ie) {
-                            // no-op
-                        }
-                    }
-                    useSharedRelrosLocked(sSharedRelros);
-                    // Clear the Bundle to ensure its file descriptor references can't be reused.
-                    sSharedRelros.clear();
-                    sSharedRelros = null;
-                }
-            }
-
-            if (NativeLibraries.sEnableLinkerTests && sTestRunnerClassName != null) {
-                // The TestRunner implementation must be instantiated _after_
-                // all libraries are loaded to ensure that its native methods
-                // are properly registered.
-                if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName);
-                TestRunner testRunner = null;
-                try {
-                    testRunner = (TestRunner)
-                            Class.forName(sTestRunnerClassName).newInstance();
-                } catch (Exception e) {
-                    Log.e(TAG, "Could not extract test runner class name", e);
-                    testRunner = null;
-                }
-                if (testRunner != null) {
-                    if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserProcess)) {
-                        Log.wtf(TAG, "Linker runtime tests failed in this process!!");
-                        assert false;
-                    } else {
-                        Log.i(TAG, "All linker tests passed!");
-                    }
-                }
-            }
-        }
-        if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
-    }
+    public abstract void finishLibraryLoad();
 
     /**
      * Call this to send a Bundle containing the shared RELRO sections to be
@@ -494,32 +328,7 @@
      * @param bundle The Bundle instance containing a map of shared RELRO sections
      * to use in this process.
      */
-    public static void useSharedRelros(Bundle bundle) {
-        // Ensure the bundle uses the application's class loader, not the framework
-        // one which doesn't know anything about LibInfo.
-        // Also, hold a fresh copy of it so the caller can't recycle it.
-        Bundle clonedBundle = null;
-        if (bundle != null) {
-            bundle.setClassLoader(LibInfo.class.getClassLoader());
-            clonedBundle = new Bundle(LibInfo.class.getClassLoader());
-            Parcel parcel = Parcel.obtain();
-            bundle.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            clonedBundle.readFromParcel(parcel);
-            parcel.recycle();
-        }
-        if (DEBUG) {
-            Log.i(TAG, "useSharedRelros() called with " + bundle
-                    + ", cloned " + clonedBundle);
-        }
-        synchronized (Linker.class) {
-            // Note that in certain cases, this can be called before
-            // initServiceProcess() in service processes.
-            sSharedRelros = clonedBundle;
-            // Tell any listener blocked in finishLibraryLoad() about it.
-            Linker.class.notifyAll();
-        }
-    }
+    public abstract void useSharedRelros(Bundle bundle);
 
     /**
      * Call this to retrieve the shared RELRO sections created in this process,
@@ -527,33 +336,13 @@
      * @return a new Bundle instance, or null if RELRO sharing is disabled on
      * this system, or if initServiceProcess() was called previously.
      */
-    public static Bundle getSharedRelros() {
-        if (DEBUG) Log.i(TAG, "getSharedRelros() called");
-        synchronized (Linker.class) {
-            if (!sInBrowserProcess) {
-                if (DEBUG) Log.i(TAG, "... returning null Bundle");
-                return null;
-            }
-
-            // Return the Bundle created in finishLibraryLoad().
-            if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
-            return sSharedRelros;
-        }
-    }
-
+    public abstract Bundle getSharedRelros();
 
     /**
      * Call this method before loading any libraries to indicate that this
      * process shall neither create or reuse shared RELRO sections.
      */
-    public static void disableSharedRelros() {
-        if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
-        synchronized (Linker.class) {
-            sInBrowserProcess = false;
-            sWaitForSharedRelros = false;
-            sBrowserUsesSharedRelro = false;
-        }
-    }
+    public abstract void disableSharedRelros();
 
     /**
      * Call this method before loading any libraries to indicate that this
@@ -561,22 +350,7 @@
      * Typically used when starting service processes.
      * @param baseLoadAddress the base library load address to use.
      */
-    public static void initServiceProcess(long baseLoadAddress) {
-        if (DEBUG) {
-            Log.i(TAG, String.format(
-                    Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
-        }
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-            sInBrowserProcess = false;
-            sBrowserUsesSharedRelro = false;
-            if (sRelroSharingSupported) {
-                sWaitForSharedRelros = true;
-                sBaseLoadAddress = baseLoadAddress;
-                sCurrentLoadAddress = baseLoadAddress;
-            }
-        }
-    }
+    public abstract void initServiceProcess(long baseLoadAddress);
 
     /**
      * Retrieve the base load address of all shared RELRO sections.
@@ -585,119 +359,7 @@
      * @return a common, random base load address, or 0 if RELRO sharing is
      * disabled.
      */
-    public static long getBaseLoadAddress() {
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-            if (!sInBrowserProcess) {
-                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
-                return 0;
-            }
-
-            setupBaseLoadAddressLocked();
-            if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
-                                                sBaseLoadAddress));
-            return sBaseLoadAddress;
-        }
-    }
-
-    // Used internally to lazily setup the common random base load address.
-    private static void setupBaseLoadAddressLocked() {
-        assert Thread.holdsLock(Linker.class);
-        if (sBaseLoadAddress == 0) {
-            long address = computeRandomBaseLoadAddress();
-            sBaseLoadAddress = address;
-            sCurrentLoadAddress = address;
-            if (address == 0) {
-                // If the computed address is 0, there are issues with finding enough
-                // free address space, so disable RELRO shared / fixed load addresses.
-                Log.w(TAG, "Disabling shared RELROs due address space pressure");
-                sBrowserUsesSharedRelro = false;
-                sWaitForSharedRelros = false;
-            }
-        }
-    }
-
-
-    /**
-     * Compute a random base load address at which to place loaded libraries.
-     * @return new base load address, or 0 if the system does not support
-     * RELRO sharing.
-     */
-    private static long computeRandomBaseLoadAddress() {
-        // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
-        // successfully mapped an area of the given size, on the basis that we will be
-        // able, with high probability, to map our library into it.
-        //
-        // One issue with this is that we do not yet know the size of the library that
-        // we will load is. So here we pass a value that we expect will always be larger
-        // than that needed. If it is smaller the library mapping may still succeed. The
-        // other issue is that although highly unlikely, there is no guarantee that
-        // something else does not map into the area we are going to use between here and
-        // when we try to map into it.
-        //
-        // The above notes mean that all of this is probablistic. It is however okay to do
-        // because if, worst case and unlikely, we get unlucky in our choice of address,
-        // the back-out and retry without the shared RELRO in the ChildProcessService will
-        // keep things running.
-        final long maxExpectedBytes = 192 * 1024 * 1024;
-        final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes);
-        if (DEBUG) {
-            Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address));
-        }
-        return address;
-    }
-
-    // Used for debugging only.
-    private static void dumpBundle(Bundle bundle) {
-        if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
-    }
-
-    /**
-     * Use the shared RELRO section from a Bundle received form another process.
-     * Call this after calling setBaseLoadAddress() then loading all libraries
-     * with loadLibrary().
-     * @param bundle Bundle instance generated with createSharedRelroBundle() in
-     * another process.
-     */
-    private static void useSharedRelrosLocked(Bundle bundle) {
-        assert Thread.holdsLock(Linker.class);
-
-        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
-
-        if (bundle == null) {
-            if (DEBUG) Log.i(TAG, "null bundle!");
-            return;
-        }
-
-        if (!sRelroSharingSupported) {
-            if (DEBUG) Log.i(TAG, "System does not support RELRO sharing");
-            return;
-        }
-
-        if (sLoadedLibraries == null) {
-            if (DEBUG) Log.i(TAG, "No libraries loaded!");
-            return;
-        }
-
-        if (DEBUG) dumpBundle(bundle);
-        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
-
-        // Apply the RELRO section to all libraries that were already loaded.
-        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
-            String libName = entry.getKey();
-            LibInfo libInfo = entry.getValue();
-            if (!nativeUseSharedRelro(libName, libInfo)) {
-                Log.w(TAG, "Could not use shared RELRO section for " + libName);
-            } else {
-                if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libName);
-            }
-        }
-
-        // In service processes, close all file descriptors from the map now.
-        if (!sInBrowserProcess) closeLibInfoMap(relroMap);
-
-        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
-    }
+    public abstract long getBaseLoadAddress();
 
     /**
      * Load a native shared library with the Chromium linker. If the zip file
@@ -709,254 +371,13 @@
      * @param zipFilePath The path of the zip file containing the library (or null).
      * @param libFilePath The path of the library (possibly in the zip file).
      */
-    public static void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
-        if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
-
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-
-            // Security: Ensure prepareLibraryLoad() was called before.
-            // In theory, this can be done lazily here, but it's more consistent
-            // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
-            // that wrap all calls to loadLibrary() in the library loader.
-            assert sPrepareLibraryLoadCalled;
-
-            if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>();
-
-            if (sLoadedLibraries.containsKey(libFilePath)) {
-                if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice");
-                return;
-            }
-
-            LibInfo libInfo = new LibInfo();
-            long loadAddress = 0;
-            if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) {
-                // Load the library at a fixed address.
-                loadAddress = sCurrentLoadAddress;
-            }
-
-            String sharedRelRoName = libFilePath;
-            if (zipFilePath != null) {
-                if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAddress, libInfo)) {
-                    String errorMessage = "Unable to load library: " + libFilePath
-                                          + ", in: " + zipFilePath;
-                    Log.e(TAG, errorMessage);
-                    throw new UnsatisfiedLinkError(errorMessage);
-                }
-                sharedRelRoName = zipFilePath;
-            } else {
-                if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
-                    String errorMessage = "Unable to load library: " + libFilePath;
-                    Log.e(TAG, errorMessage);
-                    throw new UnsatisfiedLinkError(errorMessage);
-                }
-            }
-
-            // Print the load address to the logcat when testing the linker. The format
-            // of the string is expected by the Python test_runner script as one of:
-            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
-            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
-            // Where <library-name> is the library name, and <address> is the hexadecimal load
-            // address.
-            if (NativeLibraries.sEnableLinkerTests) {
-                Log.i(TAG, String.format(
-                        Locale.US,
-                        "%s_LIBRARY_ADDRESS: %s %x",
-                        sInBrowserProcess ? "BROWSER" : "RENDERER",
-                        libFilePath,
-                        libInfo.mLoadAddress));
-            }
-
-            if (sInBrowserProcess) {
-                // Create a new shared RELRO section at the 'current' fixed load address.
-                if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddress, libInfo)) {
-                    Log.w(TAG, String.format(Locale.US,
-                            "Could not create shared RELRO for %s at %x", libFilePath,
-                            sCurrentLoadAddress));
-                } else {
-                    if (DEBUG) Log.i(TAG,
-                        String.format(
-                            Locale.US,
-                            "Created shared RELRO for %s at %x: %s",
-                            sharedRelRoName,
-                            sCurrentLoadAddress,
-                            libInfo.toString()));
-                }
-            }
-
-            if (sCurrentLoadAddress != 0) {
-                // Compute the next current load address. If sBaseLoadAddress
-                // is not 0, this is an explicit library load address. Otherwise,
-                // this is an explicit load address for relocated RELRO sections
-                // only.
-                sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
-            }
-
-            sLoadedLibraries.put(sharedRelRoName, libInfo);
-            if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString());
-        }
-    }
+    public abstract void loadLibrary(@Nullable String zipFilePath, String libFilePath);
 
     /**
      * Determine whether a library is the linker library. Also deal with the
      * component build that adds a .cr suffix to the name.
      */
-    public static boolean isChromiumLinkerLibrary(String library) {
-        return library.equals(TAG) || library.equals(TAG + ".cr");
-    }
-
-    /**
-     * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
-     *
-     * @param library The library's base name.
-     * @return the library path.
-     */
-    public static String getLibraryFilePathInZipFile(String library) throws FileNotFoundException {
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-
-            String path = nativeGetLibraryFilePathInZipFile(library);
-            if (path.equals("")) {
-                throw new FileNotFoundException(
-                        "Failed to retrieve path in zip file for library " + library);
-            }
-            return path;
-        }
-    }
-
-    /**
-     * Check whether a library is page aligned and uncompressed in the APK file.
-     *
-     * @param apkFile Filename of the APK.
-     * @param library The library's base name.
-     * @return true if page aligned and uncompressed.
-     */
-    public static boolean checkLibraryIsMappableInApk(String apkFile, String library) {
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-
-            if (DEBUG) Log.i(TAG, "checkLibraryIsMappableInApk: " + apkFile + ", " + library);
-            boolean aligned = nativeCheckLibraryIsMappableInApk(apkFile, library);
-            if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ")
-                    + "page aligned in " + apkFile);
-            return aligned;
-        }
-    }
-
-    /**
-     * Move activity from the native thread to the main UI thread.
-     * Called from native code on its own thread.  Posts a callback from
-     * the UI thread back to native code.
-     *
-     * @param opaque Opaque argument.
-     */
-    @CalledByNative
-    public static void postCallbackOnMainThread(final long opaque) {
-        ThreadUtils.postOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                nativeRunCallbackOnUiThread(opaque);
-            }
-        });
-    }
-
-    /**
-     * Native method to run callbacks on the main UI thread.
-     * Supplied by the crazy linker and called by postCallbackOnMainThread.
-     * @param opaque Opaque crazy linker arguments.
-     */
-    private static native void nativeRunCallbackOnUiThread(long opaque);
-
-    /**
-     * Native method used to load a library.
-     * @param library Platform specific library name (e.g. libfoo.so)
-     * @param loadAddress Explicit load address, or 0 for randomized one.
-     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
-     * of this LibInfo instance will set on success.
-     * @return true for success, false otherwise.
-     */
-    private static native boolean nativeLoadLibrary(String library,
-                                                    long loadAddress,
-                                                    LibInfo libInfo);
-
-    /**
-     * Native method used to load a library which is inside a zipfile.
-     * @param zipfileName Filename of the zip file containing the library.
-     * @param library Platform specific library name (e.g. libfoo.so)
-     * @param loadAddress Explicit load address, or 0 for randomized one.
-     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
-     * of this LibInfo instance will set on success.
-     * @return true for success, false otherwise.
-     */
-    private static native boolean nativeLoadLibraryInZipFile(String zipfileName,
-                                                             String libraryName,
-                                                             long loadAddress,
-                                                             LibInfo libInfo);
-
-    /**
-     * Native method used to create a shared RELRO section.
-     * If the library was already loaded at the same address using
-     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
-     * this loads a new temporary library at the specified address,
-     * creates and extracts the RELRO section from it, then unloads it.
-     * @param library Library name.
-     * @param loadAddress load address, which can be different from the one
-     * used to load the library in the current process!
-     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
-     * and mRelroFd will be set.
-     * @return true on success, false otherwise.
-     */
-    private static native boolean nativeCreateSharedRelro(String library,
-                                                          long loadAddress,
-                                                          LibInfo libInfo);
-
-    /**
-     * Native method used to use a shared RELRO section.
-     * @param library Library name.
-     * @param libInfo A LibInfo instance containing valid RELRO information
-     * @return true on success.
-     */
-    private static native boolean nativeUseSharedRelro(String library,
-                                                       LibInfo libInfo);
-
-    /**
-     * Checks that the system supports shared RELROs. Old Android kernels
-     * have a bug in the way they check Ashmem region protection flags, which
-     * makes using shared RELROs unsafe. This method performs a simple runtime
-     * check for this misfeature, even though nativeEnableSharedRelro() will
-     * always fail if this returns false.
-     */
-    private static native boolean nativeCanUseSharedRelro();
-
-    /**
-     * Return a random address that should be free to be mapped with the given size.
-     * Maps an area of size bytes, and if successful then unmaps it and returns
-     * the address of the area allocated by the system (with ASLR). The idea is
-     * that this area should remain free of other mappings until we map our library
-     * into it.
-     * @param sizeBytes Size of area in bytes to search for.
-     * @return address to pass to future mmap, or 0 on error.
-     */
-    private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
-
-    /**
-      * Native method used to get the full library path in zip file
-      * (lib/<abi>/crazy.<lib_name>).
-      *
-      * @param library The library's base name.
-      * @return the library path (or empty string on failure).
-      */
-    private static native String nativeGetLibraryFilePathInZipFile(String library);
-
-    /**
-     * Native method which checks whether a library is page aligned and
-     * uncompressed in the APK file.
-     *
-     * @param apkFile Filename of the APK.
-     * @param library The library's base name.
-     * @return true if page aligned and uncompressed.
-     */
-    private static native boolean nativeCheckLibraryIsMappableInApk(String apkFile, String library);
+    public abstract boolean isChromiumLinkerLibrary(String library);
 
     /**
      * Record information for a given library.
@@ -979,7 +400,9 @@
                 try {
                     ParcelFileDescriptor.adoptFd(mRelroFd).close();
                 } catch (java.io.IOException e) {
-                    if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd);
+                    if (DEBUG) {
+                        Log.e(TAG, "Failed to close fd: " + mRelroFd);
+                    }
                 }
                 mRelroFd = -1;
             }
@@ -1060,7 +483,7 @@
     }
 
     // Create a Bundle from a map of LibInfo objects.
-    private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
+    protected Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
         Bundle bundle = new Bundle(map.size());
         for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
             bundle.putParcelable(entry.getKey(), entry.getValue());
@@ -1070,7 +493,7 @@
     }
 
     // Create a new LibInfo map from a Bundle.
-    private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
+    protected HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
         HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
         for (String library : bundle.keySet()) {
             LibInfo libInfo = bundle.getParcelable(library);
@@ -1080,16 +503,9 @@
     }
 
     // Call the close() method on all values of a LibInfo map.
-    private static void closeLibInfoMap(HashMap<String, LibInfo> map) {
+    protected void closeLibInfoMap(HashMap<String, LibInfo> map) {
         for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
             entry.getValue().close();
         }
     }
-
-    // The map of libraries that are currently loaded in this process.
-    private static HashMap<String, LibInfo> sLoadedLibraries = null;
-
-    // Used to pass the shared RELRO Bundle through Binder.
-    public static final String EXTRA_LINKER_SHARED_RELROS =
-            "org.chromium.base.android.linker.shared_relros";
 }
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
index 24af056..1bf9c21 100644
--- a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
+++ b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
@@ -20,7 +20,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER)
+                .ensureInitialized(getInstrumentation().getTargetContext());
         RecordHistogram.initialize();
     }
 
diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
index f54944b..dad59ce 100644
--- a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
+++ b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
@@ -125,7 +125,7 @@
     // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
 
     // Exported to C++ as:
-    // Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar)
+    // Java_Example_javaMethod(JNIEnv* env, jobject caller, jint foo, jint bar)
     // Typically the C++ code would have obtained the jobject via the Init() call described above.
     @CalledByNative
     public int javaMethod(int foo, int bar) {
@@ -177,7 +177,7 @@
     // signatures. Besides these constraints the methods can be freely named.
 
     // This declares a C++ function which the application code must implement:
-    // static jint Init(JNIEnv* env, jobject obj);
+    // static jint Init(JNIEnv* env, jobject caller);
     // The jobject parameter refers back to this java side object instance.
     // The implementation must return the pointer to the C++ object cast to jint.
     // The caller of this method should store it, and supply it as a the nativeCPPClass param to
@@ -195,7 +195,7 @@
     private native void nativeDestroy(long nativeCPPClass);
 
     // This declares a C++ function which the application code must implement:
-    // static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+    // static jdouble GetDoubleFunction(JNIEnv* env, jobject caller);
     // The jobject parameter refers back to this java side object instance.
     private native double nativeGetDoubleFunction();
 
@@ -209,7 +209,7 @@
     private native void nativeSetNonPODDatatype(Rect rect);
 
     // This declares a C++ function which the application code must implement:
-    // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
+    // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject caller);
     // The jobject parameter refers back to this java side object instance.
     // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
     // deleting the JNI local reference. This is similar with Strings and arrays.
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index d1f14ba..74d0117 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -236,6 +236,9 @@
         'Ljava/lang/Object',
         'Ljava/lang/String',
         'Ljava/lang/Class',
+        'Ljava/lang/CharSequence',
+        'Ljava/lang/Runnable',
+        'Ljava/lang/Throwable',
     ]
 
     prefix = ''
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 6014847..21534ef 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -1085,29 +1085,6 @@
           TestOptions())
     self.assertRaises(SyntaxError, willRaise)
 
-  def testImplicitImport(self):
-    test_data = """
-    package org.chromium.android_webview;
-
-    %(IMPORT)s
-
-    @CalledByNative
-    private static void clientCertificatesCleared(Runnable callback) {
-        if (callbaback == null) return;
-        callback.run();
-    }
-    """
-    def generate(import_clause):
-      jni_generator.JNIFromJavaSource(
-          test_data % {'IMPORT': import_clause},
-          'org/chromium/android_webview/AwContentStatics',
-          TestOptions())
-    # Ensure it raises without the import.
-    self.assertRaises(SyntaxError, lambda: generate(''))
-
-    # Ensure it's fine with the import.
-    generate('import java.lang.Runnable;')
-
   def testSingleJNIAdditionalImport(self):
     test_data = """
     package org.chromium.foo;
diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc
index 3c5ca02..8ba77c6 100644
--- a/base/android/jni_generator/sample_for_tests.cc
+++ b/base/android/jni_generator/sample_for_tests.cc
@@ -18,7 +18,7 @@
 namespace base {
 namespace android {
 
-jdouble CPPClass::InnerClass::MethodOtherP0(JNIEnv* env, jobject obj) {
+jdouble CPPClass::InnerClass::MethodOtherP0(JNIEnv* env, jobject caller) {
   return 0.0;
 }
 
@@ -33,22 +33,22 @@
   return RegisterNativesImpl(env);  // Generated in SampleForTests_jni.h
 }
 
-void CPPClass::Destroy(JNIEnv* env, jobject obj) {
+void CPPClass::Destroy(JNIEnv* env, jobject caller) {
   delete this;
 }
 
-jint CPPClass::Method(JNIEnv* env, jobject obj) {
+jint CPPClass::Method(JNIEnv* env, jobject caller) {
   return 0;
 }
 
-void CPPClass::AddStructB(JNIEnv* env, jobject obj, jobject structb) {
+void CPPClass::AddStructB(JNIEnv* env, jobject caller, jobject structb) {
   long key = Java_InnerStructB_getKey(env, structb);
   std::string value = ConvertJavaStringToUTF8(
       env, Java_InnerStructB_getValue(env, structb).obj());
   map_[key] = value;
 }
 
-void CPPClass::IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj) {
+void CPPClass::IterateAndDoSomethingWithStructB(JNIEnv* env, jobject caller) {
   // Iterate over the elements and do something with them.
   for (std::map<long, std::string>::const_iterator it = map_.begin();
        it != map_.end(); ++it) {
@@ -59,14 +59,15 @@
 }
 
 base::android::ScopedJavaLocalRef<jstring> CPPClass::ReturnAString(
-    JNIEnv* env, jobject obj) {
+    JNIEnv* env,
+    jobject caller) {
   base::android::ScopedJavaLocalRef<jstring> ret = ConvertUTF8ToJavaString(
       env, "test");
   return ret;
 }
 
 // Static free functions declared and called directly from java.
-static jlong Init(JNIEnv* env, jobject obj, jstring param) {
+static jlong Init(JNIEnv* env, jobject caller, jstring param) {
   return 0;
 }
 
diff --git a/base/android/jni_generator/sample_for_tests.h b/base/android/jni_generator/sample_for_tests.h
index e878e56..d183c16 100644
--- a/base/android/jni_generator/sample_for_tests.h
+++ b/base/android/jni_generator/sample_for_tests.h
@@ -148,19 +148,19 @@
 
   class InnerClass {
    public:
-    jdouble MethodOtherP0(JNIEnv* env, jobject obj);
+    jdouble MethodOtherP0(JNIEnv* env, jobject caller);
   };
 
-  void Destroy(JNIEnv* env, jobject obj);
+  void Destroy(JNIEnv* env, jobject caller);
 
-  jint Method(JNIEnv* env, jobject obj);
+  jint Method(JNIEnv* env, jobject caller);
 
-  void AddStructB(JNIEnv* env, jobject obj, jobject structb);
+  void AddStructB(JNIEnv* env, jobject caller, jobject structb);
 
-  void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj);
+  void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject caller);
 
-  base::android::ScopedJavaLocalRef<jstring> ReturnAString(
-      JNIEnv* env, jobject obj);
+  base::android::ScopedJavaLocalRef<jstring> ReturnAString(JNIEnv* env,
+                                                           jobject caller);
 
  private:
   std::map<long, std::string> map_;
diff --git a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
index d3441f7..0aa9ccd 100644
--- a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
+++ b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
@@ -8,7 +8,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
-import android.view.KeyEvent;
 
 import junit.framework.Assert;
 
@@ -39,12 +38,6 @@
         public void onWindowFocusChanged(@SuppressWarnings("unused") boolean hasFocus) {
             mWindowFocusCalls++;
         }
-
-        @Implementation
-        public boolean dispatchKeyEvent(@SuppressWarnings("unused") KeyEvent event) {
-            mDispatchKeyEventCalls++;
-            return mReturnValueForKeyDispatch;
-        }
     }
 
     @Test
@@ -65,30 +58,4 @@
         // Also ensure that the original activity is forwarded the notification.
         Assert.assertEquals(1, shadow.mWindowFocusCalls);
     }
-
-    @Test
-    public void testDispatchKeyEvent() throws Exception {
-        ActivityController<Activity> controller =
-                Robolectric.buildActivity(Activity.class).create().start().visible();
-        TrackingShadowActivity shadow =
-                (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
-
-        final KeyEvent menuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
-
-        // Ensure that key events are forwarded.
-        Assert.assertFalse(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
-        // This gets called twice - once to see if the activity is swallowing it, and again to
-        // dispatch it.
-        Assert.assertEquals(2, shadow.mDispatchKeyEventCalls);
-
-        // Ensure that our activity can swallow the event.
-        shadow.mReturnValueForKeyDispatch = true;
-        Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
-        Assert.assertEquals(3, shadow.mDispatchKeyEventCalls);
-
-        // A non-enter key only dispatches once.
-        Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(
-                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
-        Assert.assertEquals(4, shadow.mDispatchKeyEventCalls);
-    }
 }
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
index 46bdc67..e5ce239 100644
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertTrue;
 
 import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
@@ -22,20 +23,6 @@
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, shadows = {LogTest.PermissiveShadowLog.class})
 public class LogTest {
-    /** Test method for {@link Log#makeTag(String)} */
-    @Test
-    public void testMakeTag() {
-        assertEquals("cr.Foo", Log.makeTag("Foo"));
-        assertEquals("cr", Log.makeTag(null));
-        assertEquals("cr", Log.makeTag(""));
-    }
-
-    /** Test method for {@link Log#makeTag(String)} */
-    @Test(expected = IllegalArgumentException.class)
-    public void testMakeTagFailure() {
-        Log.makeTag("ThisIs21Char.....Long");
-    }
-
     /** Tests that the computed call origin is the correct one. */
     @Test
     public void callOriginTest() {
@@ -88,12 +75,138 @@
         assertEquals("Bar MyThrowable MyOtherThrowable", logs.get(logs.size() - 1).msg);
     }
 
+    public void verboseLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.VERBOSE);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(Log.DEBUG, logs.get(4).type);
+        assertEquals(Log.VERBOSE, logs.get(5).type);
+        assertEquals(6, logs.size());
+    }
+
+    @Test
+    public void debugLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.DEBUG);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(Log.DEBUG, logs.get(4).type);
+        assertEquals(5, logs.size());
+    }
+
+    @Test
+    public void infoLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.INFO);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(4, logs.size());
+    }
+
+    @Test
+    public void warnLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.WARN);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(3, logs.size());
+    }
+
+    @Test
+    public void errorLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.ERROR);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(2, logs.size());
+    }
+
+    @Test
+    public void assertLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.ASSERT);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(1, logs.size());
+    }
+
+    @Before
+    public void beforeTest() {
+        PermissiveShadowLog.reset();
+    }
+
     /** Needed to allow debug/verbose logging that is disabled by default. */
     @Implements(android.util.Log.class)
     public static class PermissiveShadowLog extends ShadowLog {
+        private static int sLevel = Log.VERBOSE;
+
+        /** Sets the log level for all tags. */
+        public static void setLevel(int level) {
+            sLevel = level;
+        }
+
         @Implementation
         public static boolean isLoggable(String tag, int level) {
-            return true;
+            return level >= sLevel;
+        }
+
+        public static void reset() {
+            sLevel = Log.VERBOSE;
         }
     }
 }
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 0b59a30..0313f70 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -48,13 +48,19 @@
 
 RendererHistogramCode g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
 
+// The amount of time, in milliseconds, that it took to load the shared
+// libraries in the renderer. Set in
+// RegisterChromiumAndroidLinkerRendererHistogram.
+long g_renderer_library_load_time_ms = 0;
+
 } // namespace
 
 static void RegisterChromiumAndroidLinkerRendererHistogram(
     JNIEnv* env,
     jobject jcaller,
     jboolean requested_shared_relro,
-    jboolean load_at_fixed_address_failed) {
+    jboolean load_at_fixed_address_failed,
+    jlong library_load_time_ms) {
   // Note a pending histogram value for later recording.
   if (requested_shared_relro) {
     g_renderer_histogram_code = load_at_fixed_address_failed
@@ -62,6 +68,8 @@
   } else {
     g_renderer_histogram_code = LFA_NOT_ATTEMPTED;
   }
+
+  g_renderer_library_load_time_ms = library_load_time_ms;
 }
 
 void RecordChromiumAndroidLinkerRendererHistogram() {
@@ -72,6 +80,11 @@
                             g_renderer_histogram_code,
                             MAX_RENDERER_HISTOGRAM_CODE);
   g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
+
+  // Record how long it took to load the shared libraries.
+  UMA_HISTOGRAM_TIMES(
+      "ChromiumAndroidLinker.RendererLoadTime",
+      base::TimeDelta::FromMilliseconds(g_renderer_library_load_time_ms));
 }
 
 static void RecordChromiumAndroidLinkerBrowserHistogram(
@@ -79,7 +92,8 @@
     jobject jcaller,
     jboolean is_using_browser_shared_relros,
     jboolean load_at_fixed_address_failed,
-    jint library_load_from_apk_status) {
+    jint library_load_from_apk_status,
+    jlong library_load_time_ms) {
   // For low-memory devices, record whether or not we successfully loaded the
   // browser at a fixed address. Otherwise just record a normal invocation.
   BrowserHistogramCode histogram_code;
@@ -97,6 +111,10 @@
   UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.LibraryLoadFromApkStatus",
                             library_load_from_apk_status,
                             LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX);
+
+  // Record how long it took to load the shared libraries.
+  UMA_HISTOGRAM_TIMES("ChromiumAndroidLinker.BrowserLoadTime",
+                      base::TimeDelta::FromMilliseconds(library_load_time_ms));
 }
 
 void SetLibraryLoadedHook(LibraryLoadedHook* func) {
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index 798a283..9b54843 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -36,7 +36,7 @@
 
 bool PathMatchesSuffix(const std::string& path) {
   for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
-    if (EndsWith(path, kSuffixesToMatch[i], true)) {
+    if (EndsWith(path, kSuffixesToMatch[i], CompareCase::SENSITIVE)) {
       return true;
     }
   }
@@ -82,14 +82,14 @@
     std::vector<AddressRange>* ranges) {
   bool has_libchrome_region = false;
   for (const base::debug::MappedMemoryRegion& region : regions) {
-    if (EndsWith(region.path, kLibchromeSuffix, true)) {
+    if (EndsWith(region.path, kLibchromeSuffix, CompareCase::SENSITIVE)) {
       has_libchrome_region = true;
       break;
     }
   }
   for (const base::debug::MappedMemoryRegion& region : regions) {
     if (has_libchrome_region &&
-        !EndsWith(region.path, kLibchromeSuffix, true)) {
+        !EndsWith(region.path, kLibchromeSuffix, CompareCase::SENSITIVE)) {
       continue;
     }
     ranges->push_back(std::make_pair(region.start, region.end));
diff --git a/base/android/linker/BUILD.gn b/base/android/linker/BUILD.gn
index 190ea47..043bfc6 100644
--- a/base/android/linker/BUILD.gn
+++ b/base/android/linker/BUILD.gn
@@ -9,7 +9,7 @@
 # GYP: //base/base.gyp:chromium_android_linker
 shared_library("chromium_android_linker") {
   sources = [
-    "linker_jni.cc",
+    "legacy_linker_jni.cc",
   ]
 
   # The NDK contains the crazy_linker here:
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/legacy_linker_jni.cc
similarity index 75%
rename from base/android/linker/linker_jni.cc
rename to base/android/linker/legacy_linker_jni.cc
index 2bc480c..4612fac 100644
--- a/base/android/linker/linker_jni.cc
+++ b/base/android/linker/legacy_linker_jni.cc
@@ -22,6 +22,13 @@
 #include <sys/mman.h>
 #include <unistd.h>
 
+// See commentary in crazy_linker_elf_loader.cpp for the effect of setting
+// this.  If changing there, change here also.
+//
+// For more, see:
+//   https://crbug.com/504410
+#define RESERVE_BREAKPAD_GUARD_REGION 1
+
 // Set this to 1 to enable debug traces to the Android log.
 // Note that LOG() from "base/logging.h" cannot be used, since it is
 // in base/ which hasn't been loaded yet.
@@ -104,8 +111,8 @@
     LOG_ERROR("Could not find ID for field '%s'", field_name);
     return false;
   }
-  LOG_INFO(
-      "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name);
+  LOG_INFO("%s: Found ID %p for field '%s'", __FUNCTION__, *field_id,
+           field_name);
   return true;
 }
 
@@ -123,8 +130,8 @@
     LOG_ERROR("Could not find ID for static method '%s'", method_name);
     return false;
   }
-  LOG_INFO("%s: Found ID %p for static method '%s'",
-           __FUNCTION__, *method_id, method_name);
+  LOG_INFO("%s: Found ID %p for static method '%s'", __FUNCTION__, *method_id,
+           method_name);
   return true;
 }
 
@@ -142,9 +149,8 @@
     LOG_ERROR("Could not find ID for static field '%s'", field_name);
     return false;
   }
-  LOG_INFO(
-      "%s: Found ID %p for static field '%s'",
-      __FUNCTION__, *field_id, field_name);
+  LOG_INFO("%s: Found ID %p for static field '%s'", __FUNCTION__, *field_id,
+           field_name);
   return true;
 }
 
@@ -165,9 +171,8 @@
     return false;
 
   *value = env->GetStaticIntField(clazz, field_id);
-  LOG_INFO(
-      "%s: Found value %d for class '%s', static field '%s'",
-      __FUNCTION__, *value, class_name, field_name);
+  LOG_INFO("%s: Found value %d for class '%s', static field '%s'", __FUNCTION__,
+           *value, class_name, field_name);
 
   return true;
 }
@@ -186,7 +191,7 @@
   bool Init(JNIEnv* env) {
     jclass clazz;
     if (!InitClassReference(
-             env, "org/chromium/base/library_loader/Linker$LibInfo", &clazz)) {
+            env, "org/chromium/base/library_loader/Linker$LibInfo", &clazz)) {
       return false;
     }
 
@@ -245,8 +250,8 @@
     return false;
 
   crazy_set_sdk_build_version(static_cast<int>(value));
-  LOG_INFO("%s: Set SDK build version to %d",
-           __FUNCTION__, static_cast<int>(value));
+  LOG_INFO("%s: Set SDK build version to %d", __FUNCTION__,
+           static_cast<int>(value));
 
   return true;
 }
@@ -298,10 +303,11 @@
 namespace {
 
 template <class LibraryOpener>
-bool GenericLoadLibrary(
-    JNIEnv* env,
-    const char* library_name, jlong load_address, jobject lib_info_obj,
-    const LibraryOpener& opener) {
+bool GenericLoadLibrary(JNIEnv* env,
+                        const char* library_name,
+                        jlong load_address,
+                        jobject lib_info_obj,
+                        const LibraryOpener& opener) {
   crazy_context_t* context = GetCrazyContext();
 
   if (!IsValidAddress(load_address)) {
@@ -319,18 +325,16 @@
 
   crazy_library_info_t info;
   if (!crazy_library_get_info(library.Get(), context, &info)) {
-    LOG_ERROR("%s: Could not get library information for %s: %s",
-              __FUNCTION__,
-              library_name,
-              crazy_context_get_error(context));
+    LOG_ERROR("%s: Could not get library information for %s: %s", __FUNCTION__,
+              library_name, crazy_context_get_error(context));
     return false;
   }
 
   // Release library object to keep it alive after the function returns.
   library.Release();
 
-  s_lib_info_fields.SetLoadInfo(
-      env, lib_info_obj, info.load_address, info.load_size);
+  s_lib_info_fields.SetLoadInfo(env, lib_info_obj, info.load_address,
+                                info.load_size);
   LOG_INFO("%s: Success loading library %s", __FUNCTION__, library_name);
   return true;
 }
@@ -338,20 +342,16 @@
 // Used for opening the library in a regular file.
 class FileLibraryOpener {
  public:
-  bool Open(
-      crazy_library_t** library,
-      const char* library_name,
-      crazy_context_t* context) const;
+  bool Open(crazy_library_t** library,
+            const char* library_name,
+            crazy_context_t* context) const;
 };
 
-bool FileLibraryOpener::Open(
-    crazy_library_t** library,
-    const char* library_name,
-    crazy_context_t* context) const {
+bool FileLibraryOpener::Open(crazy_library_t** library,
+                             const char* library_name,
+                             crazy_context_t* context) const {
   if (!crazy_library_open(library, library_name, context)) {
-    LOG_ERROR("%s: Could not open %s: %s",
-              __FUNCTION__,
-              library_name,
+    LOG_ERROR("%s: Could not open %s: %s", __FUNCTION__, library_name,
               crazy_context_get_error(context));
     return false;
   }
@@ -362,24 +362,22 @@
 class ZipLibraryOpener {
  public:
   explicit ZipLibraryOpener(const char* zip_file) : zip_file_(zip_file) {}
-  bool Open(
-      crazy_library_t** library,
-      const char* library_name,
-      crazy_context_t* context) const;
+  bool Open(crazy_library_t** library,
+            const char* library_name,
+            crazy_context_t* context) const;
+
  private:
   const char* zip_file_;
 };
 
-bool ZipLibraryOpener::Open(
-    crazy_library_t** library,
-    const char* library_name,
-    crazy_context_t* context) const {
-  if (!crazy_library_open_in_zip_file(
-          library, zip_file_, library_name, context)) {
-     LOG_ERROR("%s: Could not open %s in zip file %s: %s",
-               __FUNCTION__, library_name, zip_file_,
-               crazy_context_get_error(context));
-     return false;
+bool ZipLibraryOpener::Open(crazy_library_t** library,
+                            const char* library_name,
+                            crazy_context_t* context) const {
+  if (!crazy_library_open_in_zip_file(library, zip_file_, library_name,
+                                      context)) {
+    LOG_ERROR("%s: Could not open %s in zip file %s: %s", __FUNCTION__,
+              library_name, zip_file_, crazy_context_get_error(context));
+    return false;
   }
   return true;
 }
@@ -406,9 +404,9 @@
                      jobject lib_info_obj) {
   String lib_name(env, library_name);
   FileLibraryOpener opener;
-  return GenericLoadLibrary(
-      env, lib_name.c_str(),
-      static_cast<size_t>(load_address), lib_info_obj, opener);
+  return GenericLoadLibrary(env, lib_name.c_str(),
+                            static_cast<size_t>(load_address), lib_info_obj,
+                            opener);
 }
 
 // Load a library from a zipfile with the chromium linker. The
@@ -442,9 +440,9 @@
   String zipfile_name_str(env, zipfile_name);
   String lib_name(env, library_name);
   ZipLibraryOpener opener(zipfile_name_str.c_str());
-  return GenericLoadLibrary(
-      env, lib_name.c_str(),
-      static_cast<size_t>(load_address), lib_info_obj, opener);
+  return GenericLoadLibrary(env, lib_name.c_str(),
+                            static_cast<size_t>(load_address), lib_info_obj,
+                            opener);
 }
 
 // Class holding the Java class and method ID for the Java side Linker
@@ -456,11 +454,8 @@
   // Initialize an instance.
   bool Init(JNIEnv* env, jclass linker_class) {
     clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class));
-    return InitStaticMethodId(env,
-                              linker_class,
-                              "postCallbackOnMainThread",
-                              "(J)V",
-                              &method_id);
+    return InitStaticMethodId(env, linker_class, "postCallbackOnMainThread",
+                              "(J)V", &method_id);
   }
 };
 
@@ -475,8 +470,8 @@
 void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) {
   crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg);
 
-  LOG_INFO("%s: Called back from java with handler %p, opaque %p",
-           __FUNCTION__, callback->handler, callback->opaque);
+  LOG_INFO("%s: Called back from java with handler %p, opaque %p", __FUNCTION__,
+           callback->handler, callback->opaque);
 
   crazy_callback_run(callback);
   delete callback;
@@ -496,14 +491,13 @@
 
   JavaVM* vm;
   int minimum_jni_version;
-  crazy_context_get_java_vm(context,
-                            reinterpret_cast<void**>(&vm),
+  crazy_context_get_java_vm(context, reinterpret_cast<void**>(&vm),
                             &minimum_jni_version);
 
   // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own.
   JNIEnv* env;
-  if (JNI_OK != vm->GetEnv(
-      reinterpret_cast<void**>(&env), minimum_jni_version)) {
+  if (JNI_OK !=
+      vm->GetEnv(reinterpret_cast<void**>(&env), minimum_jni_version)) {
     LOG_ERROR("Could not create JNIEnv");
     return false;
   }
@@ -512,13 +506,13 @@
   crazy_callback_t* callback = new crazy_callback_t();
   *callback = *callback_request;
 
-  LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
-           __FUNCTION__, callback->handler, callback->opaque);
+  LOG_INFO("%s: Calling back to java with handler %p, opaque %p", __FUNCTION__,
+           callback->handler, callback->opaque);
 
   jlong arg = static_cast<jlong>(reinterpret_cast<uintptr_t>(callback));
 
-  env->CallStaticVoidMethod(
-      s_java_callback_bindings.clazz, s_java_callback_bindings.method_id, arg);
+  env->CallStaticVoidMethod(s_java_callback_bindings.clazz,
+                            s_java_callback_bindings.method_id, arg);
 
   // Back out and return false if we encounter a JNI exception.
   if (env->ExceptionCheck() == JNI_TRUE) {
@@ -556,21 +550,16 @@
   size_t relro_size = 0;
   int relro_fd = -1;
 
-  if (!crazy_library_create_shared_relro(library.Get(),
-                                         context,
-                                         static_cast<size_t>(load_address),
-                                         &relro_start,
-                                         &relro_size,
-                                         &relro_fd)) {
+  if (!crazy_library_create_shared_relro(
+          library.Get(), context, static_cast<size_t>(load_address),
+          &relro_start, &relro_size, &relro_fd)) {
     LOG_ERROR("%s: Could not create shared RELRO sharing for %s: %s\n",
-              __FUNCTION__,
-              lib_name.c_str(),
-              crazy_context_get_error(context));
+              __FUNCTION__, lib_name.c_str(), crazy_context_get_error(context));
     return false;
   }
 
-  s_lib_info_fields.SetRelroInfo(
-      env, lib_info_obj, relro_start, relro_size, relro_fd);
+  s_lib_info_fields.SetRelroInfo(env, lib_info_obj, relro_start, relro_size,
+                                 relro_fd);
   return true;
 }
 
@@ -580,9 +569,7 @@
                         jobject lib_info_obj) {
   String lib_name(env, library_name);
 
-  LOG_INFO("%s: called for %s, lib_info_ref=%p",
-           __FUNCTION__,
-           lib_name.c_str(),
+  LOG_INFO("%s: called for %s, lib_info_ref=%p", __FUNCTION__, lib_name.c_str(),
            lib_info_obj);
 
   ScopedLibrary library;
@@ -595,27 +582,20 @@
   size_t relro_start = 0;
   size_t relro_size = 0;
   int relro_fd = -1;
-  s_lib_info_fields.GetRelroInfo(
-      env, lib_info_obj, &relro_start, &relro_size, &relro_fd);
+  s_lib_info_fields.GetRelroInfo(env, lib_info_obj, &relro_start, &relro_size,
+                                 &relro_fd);
 
-  LOG_INFO("%s: library=%s relro start=%p size=%p fd=%d",
-           __FUNCTION__,
-           lib_name.c_str(),
-           (void*)relro_start,
-           (void*)relro_size,
-           relro_fd);
+  LOG_INFO("%s: library=%s relro start=%p size=%p fd=%d", __FUNCTION__,
+           lib_name.c_str(), (void*)relro_start, (void*)relro_size, relro_fd);
 
-  if (!crazy_library_use_shared_relro(
-           library.Get(), context, relro_start, relro_size, relro_fd)) {
-    LOG_ERROR("%s: Could not use shared RELRO for %s: %s",
-              __FUNCTION__,
-              lib_name.c_str(),
-              crazy_context_get_error(context));
+  if (!crazy_library_use_shared_relro(library.Get(), context, relro_start,
+                                      relro_size, relro_fd)) {
+    LOG_ERROR("%s: Could not use shared RELRO for %s: %s", __FUNCTION__,
+              lib_name.c_str(), crazy_context_get_error(context));
     return false;
   }
 
-  LOG_INFO("%s: Library %s using shared RELRO section!",
-           __FUNCTION__,
+  LOG_INFO("%s: Library %s using shared RELRO section!", __FUNCTION__,
            lib_name.c_str());
 
   return true;
@@ -626,6 +606,13 @@
 }
 
 jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) {
+#if RESERVE_BREAKPAD_GUARD_REGION
+  // Add a Breakpad guard region.  16Mb should be comfortably larger than
+  // the largest relocation packer saving we expect to encounter.
+  static const size_t kBreakpadGuardRegionBytes = 16 * 1024 * 1024;
+  bytes += kBreakpadGuardRegionBytes;
+#endif
+
   void* address =
       mmap(NULL, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (address == MAP_FAILED) {
@@ -633,56 +620,17 @@
     return 0;
   }
   munmap(address, bytes);
+
+#if RESERVE_BREAKPAD_GUARD_REGION
+  // Allow for a Breakpad guard region ahead of the returned address.
+  address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) +
+                                    kBreakpadGuardRegionBytes);
+#endif
+
   LOG_INFO("%s: Random base load address is %p\n", __FUNCTION__, address);
   return static_cast<jlong>(reinterpret_cast<uintptr_t>(address));
 }
 
-// Get the full path of a library in the zip file
-// (lib/<abi>/crazy.<lib_name>).
-//
-// |env| is the current JNI environment handle.
-// |clazz| is the static class handle which is not used here.
-// |lib_name| is the library base name.
-// Returns the full path (or empty string on failure).
-jstring GetLibraryFilePathInZipFile(JNIEnv* env,
-                                    jclass clazz,
-                                    jstring lib_name) {
-  String lib_name_str(env, lib_name);
-  const char* lib_name_c_str = lib_name_str.c_str();
-  char buffer[kMaxFilePathLengthInZip + 1];
-  if (crazy_library_file_path_in_zip_file(
-          lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) {
-    LOG_ERROR("%s: Failed to get full filename for library '%s'",
-              __FUNCTION__, lib_name_c_str);
-    buffer[0] = '\0';
-  }
-  return env->NewStringUTF(buffer);
-}
-
-// Check whether a library is page aligned and uncompressed in the APK file.
-//
-// |env| is the current JNI environment handle.
-// |clazz| is the static class handle which is not used here.
-// |apkfile_name| is the filename of the APK.
-// |library_name| is the library base name.
-// Returns true if page aligned and uncompressed.
-jboolean CheckLibraryIsMappableInApk(JNIEnv* env, jclass clazz,
-                                     jstring apkfile_name,
-                                     jstring library_name) {
-  String apkfile_name_str(env, apkfile_name);
-  const char* apkfile_name_c_str = apkfile_name_str.c_str();
-  String library_name_str(env, library_name);
-  const char* library_name_c_str = library_name_str.c_str();
-
-  LOG_INFO("%s: Checking if %s is page-aligned and uncompressed in %s\n",
-           __FUNCTION__, library_name_c_str, apkfile_name_c_str);
-  jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file(
-      apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS;
-  LOG_INFO("%s: %s\n", __FUNCTION__, mappable ? "Mappable" : "NOT mappable");
-
-  return mappable;
-}
-
 const JNINativeMethod kNativeMethods[] = {
     {"nativeLoadLibrary",
      "("
@@ -733,19 +681,7 @@
      ")"
      "J",
      reinterpret_cast<void*>(&GetRandomBaseLoadAddress)},
-    {"nativeGetLibraryFilePathInZipFile",
-     "("
-     "Ljava/lang/String;"
-     ")"
-     "Ljava/lang/String;",
-     reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)},
-    {"nativeCheckLibraryIsMappableInApk",
-     "("
-     "Ljava/lang/String;"
-     "Ljava/lang/String;"
-     ")"
-     "Z",
-     reinterpret_cast<void*>(&CheckLibraryIsMappableInApk)}, };
+};
 
 }  // namespace
 
@@ -768,14 +704,12 @@
 
   // Register native methods.
   jclass linker_class;
-  if (!InitClassReference(env,
-                          "org/chromium/base/library_loader/Linker",
+  if (!InitClassReference(env, "org/chromium/base/library_loader/LegacyLinker",
                           &linker_class))
     return -1;
 
   LOG_INFO("%s: Registering native methods", __FUNCTION__);
-  env->RegisterNatives(linker_class,
-                       kNativeMethods,
+  env->RegisterNatives(linker_class, kNativeMethods,
                        sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
 
   // Find LibInfo field ids.
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
index c98007c..caad53a 100644
--- a/base/android/path_utils.cc
+++ b/base/android/path_utils.cc
@@ -41,6 +41,16 @@
   return true;
 }
 
+bool GetThumbnailCacheDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getThumbnailCacheDirectoryPath(env,
+                                                    GetApplicationContext());
+  FilePath thumbnail_cache_path(ConvertJavaStringToUTF8(path));
+  *result = thumbnail_cache_path;
+  return true;
+}
+
 bool GetDownloadsDirectory(FilePath* result) {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jstring> path =
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
index d3421b3..6501f1b 100644
--- a/base/android/path_utils.h
+++ b/base/android/path_utils.h
@@ -31,6 +31,10 @@
 // cache dir.
 BASE_EXPORT bool GetCacheDirectory(FilePath* result);
 
+// Retrieves the path to the thumbnail cache directory. The result is placed
+// in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetThumbnailCacheDirectory(FilePath* result);
+
 // Retrieves the path to the public downloads directory. The result is placed
 // in the FilePath pointed to by 'result'.
 BASE_EXPORT bool GetDownloadsDirectory(FilePath* result);
diff --git a/base/android/trace_event_binding.cc b/base/android/trace_event_binding.cc
index 791b67f..3c5ee17 100644
--- a/base/android/trace_event_binding.cc
+++ b/base/android/trace_event_binding.cc
@@ -8,6 +8,7 @@
 
 #include <set>
 
+#include "base/android/jni_string.h"
 #include "base/lazy_instance.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_impl.h"
@@ -25,32 +26,28 @@
 // Boilerplate for safely converting Java data to TRACE_EVENT data.
 class TraceEventDataConverter {
  public:
-  TraceEventDataConverter(JNIEnv* env,
-                          jstring jname,
-                          jstring jarg)
+  TraceEventDataConverter(JNIEnv* env, jstring jname, jstring jarg)
       : env_(env),
         jname_(jname),
         jarg_(jarg),
-        name_(env->GetStringUTFChars(jname, NULL)),
-        arg_(jarg ? env->GetStringUTFChars(jarg, NULL) : NULL) {
-  }
+        name_(ConvertJavaStringToUTF8(env, jname)),
+        has_arg_(jarg != nullptr),
+        arg_(jarg ? ConvertJavaStringToUTF8(env, jarg) : "") {}
   ~TraceEventDataConverter() {
-    env_->ReleaseStringUTFChars(jname_, name_);
-    if (jarg_)
-      env_->ReleaseStringUTFChars(jarg_, arg_);
   }
 
   // Return saves values to pass to TRACE_EVENT macros.
-  const char* name() { return name_; }
-  const char* arg_name() { return arg_ ? "arg" : NULL; }
-  const char* arg() { return arg_; }
+  const char* name() { return name_.c_str(); }
+  const char* arg_name() { return has_arg_ ? "arg" : nullptr; }
+  const char* arg() { return has_arg_ ? arg_.c_str() : nullptr; }
 
  private:
   JNIEnv* env_;
   jstring jname_;
   jstring jarg_;
-  const char* name_;
-  const char* arg_;
+  std::string name_;
+  bool has_arg_;
+  std::string arg_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
 };
diff --git a/base/atomicops.h b/base/atomicops.h
index 6a5371c..f983b45 100644
--- a/base/atomicops.h
+++ b/base/atomicops.h
@@ -144,33 +144,6 @@
 }  // namespace subtle
 }  // namespace base
 
-// The following x86 CPU features are used in atomicops_internals_x86_gcc.h, but
-// this file is duplicated inside of Chrome: protobuf and tcmalloc rely on the
-// struct being present at link time. Some parts of Chrome can currently use the
-// portable interface whereas others still use GCC one. The include guards are
-// the same as in atomicops_internals_x86_gcc.cc.
-#if defined(__i386__) || defined(__x86_64__)
-// This struct is not part of the public API of this module; clients may not
-// use it.  (However, it's exported via BASE_EXPORT because clients implicitly
-// do use it at link time by inlining these functions.)
-// Features of this x86.  Values may not be correct before main() is run,
-// but are set conservatively.
-struct AtomicOps_x86CPUFeatureStruct {
-  bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
-                            // after acquire compare-and-swap.
-  // The following fields are unused by Chrome's base implementation but are
-  // still used by copies of the same code in other parts of the code base. This
-  // causes an ODR violation, and the other code is likely reading invalid
-  // memory.
-  // TODO(jfb) Delete these fields once the rest of the Chrome code base doesn't
-  //           depend on them.
-  bool has_sse2;            // Processor has SSE2.
-  bool has_cmpxchg16b;      // Processor supports cmpxchg16b instruction.
-};
-BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
-    AtomicOps_Internalx86CPUFeatures;
-#endif
-
 // Try to use a portable implementation based on C++11 atomics.
 //
 // Some toolchains support C++11 language features without supporting library
@@ -188,17 +161,6 @@
 #    include "base/atomicops_internals_x86_msvc.h"
 #  elif defined(OS_MACOSX)
 #    include "base/atomicops_internals_mac.h"
-#  elif defined(OS_NACL)
-#    include "base/atomicops_internals_gcc.h"
-#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
-#    include "base/atomicops_internals_arm_gcc.h"
-#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
-#    include "base/atomicops_internals_arm64_gcc.h"
-#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
-#    include "base/atomicops_internals_x86_gcc.h"
-#  elif (defined(COMPILER_GCC) && \
-         (defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)))
-#    include "base/atomicops_internals_mips_gcc.h"
 #  else
 #    error "Atomic operations are not supported on your platform"
 #  endif
diff --git a/base/atomicops_internals_arm64_gcc.h b/base/atomicops_internals_arm64_gcc.h
deleted file mode 100644
index ddcfec9..0000000
--- a/base/atomicops_internals_arm64_gcc.h
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-
-// TODO(rmcilroy): Investigate whether we can use __sync__ intrinsics instead of
-//                 the hand coded assembly without introducing perf regressions.
-// TODO(rmcilroy): Investigate whether we can use acquire / release versions of
-//                 exclusive load / store assembly instructions and do away with
-//                 the barriers.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
-
-#if defined(OS_QNX)
-#include <sys/cpuinline.h>
-#endif
-
-namespace base {
-namespace subtle {
-
-inline void MemoryBarrier() {
-  __asm__ __volatile__ ("dmb ish" ::: "memory");  // NOLINT
-}
-
-// NoBarrier versions of the operation include "memory" in the clobber list.
-// This is not required for direct usage of the NoBarrier versions of the
-// operations. However this is required for correctness when they are used as
-// part of the Acquire or Release versions, to ensure that nothing from outside
-// the call is reordered between the operation and the memory barrier. This does
-// not change the code generated, so has no or minimal impact on the
-// NoBarrier operations.
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %w[prev], %[ptr]                 \n\t"  // Load the previous value.
-    "cmp %w[prev], %w[old_value]           \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
-    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
-    "1:                                    \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"IJr" (old_value),
-      [new_value]"r" (new_value)
-    : "cc", "memory"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %w[result], %[ptr]               \n\t"  // Load the previous value.
-    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
-    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [new_value]"r" (new_value)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                       \n\t"
-    "ldxr %w[result], %[ptr]                  \n\t"  // Load the previous value.
-    "add %w[result], %w[result], %w[increment]\n\t"
-    "stxr %w[temp], %w[result], %[ptr]        \n\t"  // Try to store the result.
-    "cbnz %w[temp], 0b                        \n\t"  // Retry on failure.
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [increment]"IJr" (increment)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  MemoryBarrier();
-  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-
-  return result;
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-
-  return prev;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  MemoryBarrier();
-  Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-
-  return prev;
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  __asm__ __volatile__ (  // NOLINT
-    "stlr %w[value], %[ptr]  \n\t"
-    : [ptr]"=Q" (*ptr)
-    : [value]"r" (value)
-    : "memory"
-  );  // NOLINT
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value;
-
-  __asm__ __volatile__ (  // NOLINT
-    "ldar %w[value], %[ptr]  \n\t"
-    : [value]"=r" (value)
-    : [ptr]"Q" (*ptr)
-    : "memory"
-  );  // NOLINT
-
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-// 64-bit versions of the operations.
-// See the 32-bit versions for comments.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %[prev], %[ptr]                  \n\t"
-    "cmp %[prev], %[old_value]             \n\t"
-    "bne 1f                                \n\t"
-    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
-    "cbnz %w[temp], 0b                     \n\t"
-    "1:                                    \n\t"
-    : [prev]"=&r" (prev),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [old_value]"IJr" (old_value),
-      [new_value]"r" (new_value)
-    : "cc", "memory"
-  );  // NOLINT
-
-  return prev;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  Atomic64 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                    \n\t"
-    "ldxr %[result], %[ptr]                \n\t"
-    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
-    "cbnz %w[temp], 0b                     \n\t"
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [new_value]"r" (new_value)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  Atomic64 result;
-  int32_t temp;
-
-  __asm__ __volatile__ (  // NOLINT
-    "0:                                     \n\t"
-    "ldxr %[result], %[ptr]                 \n\t"
-    "add %[result], %[result], %[increment] \n\t"
-    "stxr %w[temp], %[result], %[ptr]       \n\t"
-    "cbnz %w[temp], 0b                      \n\t"
-    : [result]"=&r" (result),
-      [temp]"=&r" (temp),
-      [ptr]"+Q" (*ptr)
-    : [increment]"IJr" (increment)
-    : "memory"
-  );  // NOLINT
-
-  return result;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  MemoryBarrier();
-  Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-
-  return result;
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-
-  return prev;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  MemoryBarrier();
-  Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-
-  return prev;
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  __asm__ __volatile__ (  // NOLINT
-    "stlr %x[value], %[ptr]  \n\t"
-    : [ptr]"=Q" (*ptr)
-    : [value]"r" (value)
-    : "memory"
-  );  // NOLINT
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value;
-
-  __asm__ __volatile__ (  // NOLINT
-    "ldar %x[value], %[ptr]  \n\t"
-    : [value]"=r" (value)
-    : [ptr]"Q" (*ptr)
-    : "memory"
-  );  // NOLINT
-
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-}  // namespace subtle
-}  // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h
deleted file mode 100644
index 44c91c8..0000000
--- a/base/atomicops_internals_arm_gcc.h
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2013 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 is an internal atomic implementation, use base/atomicops.h instead.
-//
-// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
-
-#if defined(OS_QNX)
-#include <sys/cpuinline.h>
-#endif
-
-namespace base {
-namespace subtle {
-
-// Memory barriers on ARM are funky, but the kernel is here to help:
-//
-// * ARMv5 didn't support SMP, there is no memory barrier instruction at
-//   all on this architecture, or when targeting its machine code.
-//
-// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by
-//   writing a random value to a very specific coprocessor register.
-//
-// * On ARMv7, the "dmb" instruction is used to perform a full memory
-//   barrier (though writing to the co-processor will still work).
-//   However, on single core devices (e.g. Nexus One, or Nexus S),
-//   this instruction will take up to 200 ns, which is huge, even though
-//   it's completely un-needed on these devices.
-//
-// * There is no easy way to determine at runtime if the device is
-//   single or multi-core. However, the kernel provides a useful helper
-//   function at a fixed memory address (0xffff0fa0), which will always
-//   perform a memory barrier in the most efficient way. I.e. on single
-//   core devices, this is an empty function that exits immediately.
-//   On multi-core devices, it implements a full memory barrier.
-//
-// * This source could be compiled to ARMv5 machine code that runs on a
-//   multi-core ARMv6 or ARMv7 device. In this case, memory barriers
-//   are needed for correct execution. Always call the kernel helper, even
-//   when targeting ARMv5TE.
-//
-
-inline void MemoryBarrier() {
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-  // Note: This is a function call, which is also an implicit compiler barrier.
-  typedef void (*KernelMemoryBarrierFunc)();
-  ((KernelMemoryBarrierFunc)0xffff0fa0)();
-#elif defined(OS_QNX)
-  __cpu_membarrier();
-#else
-#error MemoryBarrier() is not implemented on this platform.
-#endif
-}
-
-// An ARM toolchain would only define one of these depending on which
-// variant of the target architecture is being used. This tests against
-// any known ARMv6 or ARMv7 variant, where it is possible to directly
-// use ldrex/strex instructions to implement fast atomic operations.
-#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
-    defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \
-    defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
-    defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
-    defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev_value;
-  int reloop;
-  do {
-    // The following is equivalent to:
-    //
-    //   prev_value = LDREX(ptr)
-    //   reloop = 0
-    //   if (prev_value != old_value)
-    //      reloop = STREX(ptr, new_value)
-    __asm__ __volatile__("    ldrex %0, [%3]\n"
-                         "    mov %1, #0\n"
-                         "    cmp %0, %4\n"
-#ifdef __thumb2__
-                         "    it eq\n"
-#endif
-                         "    strexeq %1, %5, [%3]\n"
-                         : "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr)
-                         : "r"(ptr), "r"(old_value), "r"(new_value)
-                         : "cc", "memory");
-  } while (reloop != 0);
-  return prev_value;
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-  return result;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  MemoryBarrier();
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 value;
-  int reloop;
-  do {
-    // Equivalent to:
-    //
-    //  value = LDREX(ptr)
-    //  value += increment
-    //  reloop = STREX(ptr, value)
-    //
-    __asm__ __volatile__("    ldrex %0, [%3]\n"
-                         "    add %0, %0, %4\n"
-                         "    strex %1, %0, [%3]\n"
-                         : "=&r"(value), "=&r"(reloop), "+m"(*ptr)
-                         : "r"(ptr), "r"(increment)
-                         : "cc", "memory");
-  } while (reloop);
-  return value;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  // TODO(digit): Investigate if it's possible to implement this with
-  // a single MemoryBarrier() operation between the LDREX and STREX.
-  // See http://crbug.com/246514
-  MemoryBarrier();
-  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-  return result;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 old_value;
-  int reloop;
-  do {
-    // old_value = LDREX(ptr)
-    // reloop = STREX(ptr, new_value)
-    __asm__ __volatile__("   ldrex %0, [%3]\n"
-                         "   strex %1, %4, [%3]\n"
-                         : "=&r"(old_value), "=&r"(reloop), "+m"(*ptr)
-                         : "r"(ptr), "r"(new_value)
-                         : "cc", "memory");
-  } while (reloop != 0);
-  return old_value;
-}
-
-// This tests against any known ARMv5 variant.
-#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
-      defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
-
-// The kernel also provides a helper function to perform an atomic
-// compare-and-swap operation at the hard-wired address 0xffff0fc0.
-// On ARMv5, this is implemented by a special code path that the kernel
-// detects and treats specially when thread pre-emption happens.
-// On ARMv6 and higher, it uses LDREX/STREX instructions instead.
-//
-// Note that this always perform a full memory barrier, there is no
-// need to add calls MemoryBarrier() before or after it. It also
-// returns 0 on success, and 1 on exit.
-//
-// Available and reliable since Linux 2.6.24. Both Android and ChromeOS
-// use newer kernel revisions, so this should not be a concern.
-namespace {
-
-inline int LinuxKernelCmpxchg(Atomic32 old_value,
-                              Atomic32 new_value,
-                              volatile Atomic32* ptr) {
-  typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*);
-  return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr);
-}
-
-}  // namespace
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev_value;
-  for (;;) {
-    prev_value = *ptr;
-    if (prev_value != old_value)
-      return prev_value;
-    if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
-      return old_value;
-  }
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 old_value;
-  do {
-    old_value = *ptr;
-  } while (LinuxKernelCmpxchg(old_value, new_value, ptr));
-  return old_value;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  for (;;) {
-    // Atomic exchange the old value with an incremented one.
-    Atomic32 old_value = *ptr;
-    Atomic32 new_value = old_value + increment;
-    if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) {
-      // The exchange took place as expected.
-      return new_value;
-    }
-    // Otherwise, *ptr changed mid-loop and we need to retry.
-  }
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 prev_value;
-  for (;;) {
-    prev_value = *ptr;
-    if (prev_value != old_value) {
-      // Always ensure acquire semantics.
-      MemoryBarrier();
-      return prev_value;
-    }
-    if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
-      return old_value;
-  }
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  // This could be implemented as:
-  //    MemoryBarrier();
-  //    return NoBarrier_CompareAndSwap();
-  //
-  // But would use 3 barriers per succesful CAS. To save performance,
-  // use Acquire_CompareAndSwap(). Its implementation guarantees that:
-  // - A succesful swap uses only 2 barriers (in the kernel helper).
-  // - An early return due to (prev_value != old_value) performs
-  //   a memory barrier with no store, which is equivalent to the
-  //   generic implementation above.
-  return Acquire_CompareAndSwap(ptr, old_value, new_value);
-}
-
-#else
-#  error "Your CPU's ARM architecture is not supported yet"
-#endif
-
-// NOTE: Atomicity of the following load and store operations is only
-// guaranteed in case of 32-bit alignement of |ptr| values.
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-}  // namespace subtle
-}  // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/base/atomicops_internals_gcc.h b/base/atomicops_internals_gcc.h
deleted file mode 100644
index 35c95fe..0000000
--- a/base/atomicops_internals_gcc.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2009 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 is an internal atomic implementation, include base/atomicops.h
-// instead. This file is for platforms that use GCC intrinsics rather than
-// platform-specific assembly code for atomic operations.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_GCC_H_
-
-namespace base {
-namespace subtle {
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev_value;
-  do {
-    if (__sync_bool_compare_and_swap(ptr, old_value, new_value))
-      return old_value;
-    prev_value = *ptr;
-  } while (prev_value == old_value);
-  return prev_value;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 old_value;
-  do {
-    old_value = *ptr;
-  } while (!__sync_bool_compare_and_swap(ptr, old_value, new_value));
-  return old_value;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  return Barrier_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  for (;;) {
-    // Atomic exchange the old value with an incremented one.
-    Atomic32 old_value = *ptr;
-    Atomic32 new_value = old_value + increment;
-    if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
-      // The exchange took place as expected.
-      return new_value;
-    }
-    // Otherwise, *ptr changed mid-loop and we need to retry.
-  }
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  // Since NoBarrier_CompareAndSwap uses __sync_bool_compare_and_swap, which
-  // is a full memory barrier, none is needed here or below in Release.
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void MemoryBarrier() {
-  __sync_synchronize();
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-}  // namespace subtle
-}  // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_GCC_H_
-
diff --git a/base/atomicops_internals_mips_gcc.h b/base/atomicops_internals_mips_gcc.h
deleted file mode 100644
index b4551b8..0000000
--- a/base/atomicops_internals_mips_gcc.h
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-//
-// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
-
-namespace base {
-namespace subtle {
-
-// Atomically execute:
-//      result = *ptr;
-//      if (*ptr == old_value)
-//        *ptr = new_value;
-//      return result;
-//
-// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
-// Always return the old value of "*ptr"
-//
-// This routine implies no memory barriers.
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev, tmp;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "ll %0, %5\n"  // prev = *ptr
-                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
-                       "move %2, %4\n"  // tmp = new_value
-                       "sc %2, %1\n"  // *ptr = tmp (with atomic check)
-                       "beqz %2, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       "2:\n"
-                       ".set pop\n"
-                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
-                       : "r" (old_value), "r" (new_value), "m" (*ptr)
-                       : "memory");
-  return prev;
-}
-
-// Atomically store new_value into *ptr, returning the previous value held in
-// *ptr.  This routine implies no memory barriers.
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  Atomic32 temp, old;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "ll %1, %4\n"  // old = *ptr
-                       "move %0, %3\n"  // temp = new_value
-                       "sc %0, %2\n"  // *ptr = temp (with atomic check)
-                       "beqz %0, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
-                       : "r" (new_value), "m" (*ptr)
-                       : "memory");
-
-  return old;
-}
-
-// Atomically increment *ptr by "increment".  Returns the new value of
-// *ptr with the increment applied.  This routine implies no memory barriers.
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 temp, temp2;
-
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "ll %0, %4\n"  // temp = *ptr
-                       "addu %1, %0, %3\n"  // temp2 = temp + increment
-                       "sc %1, %2\n"  // *ptr = temp2 (with atomic check)
-                       "beqz %1, 1b\n"  // start again on atomic error
-                       "addu %1, %0, %3\n"  // temp2 = temp + increment
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
-                       : "Ir" (increment), "m" (*ptr)
-                       : "memory");
-  // temp2 now holds the final value.
-  return temp2;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  MemoryBarrier();
-  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-  return res;
-}
-
-// "Acquire" operations
-// ensure that no later memory access can be reordered ahead of the operation.
-// "Release" operations ensure that no previous memory access can be reordered
-// after the operation.  "Barrier" operations have both "Acquire" and "Release"
-// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
-// access.
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-  return res;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  MemoryBarrier();
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void MemoryBarrier() {
-  __asm__ __volatile__("sync" : : : "memory");
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#if defined(__LP64__)
-// 64-bit versions of the atomic ops.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev, tmp;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "lld %0, %5\n"  // prev = *ptr
-                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
-                       "move %2, %4\n"  // tmp = new_value
-                       "scd %2, %1\n"  // *ptr = tmp (with atomic check)
-                       "beqz %2, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       "2:\n"
-                       ".set pop\n"
-                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
-                       : "r" (old_value), "r" (new_value), "m" (*ptr)
-                       : "memory");
-  return prev;
-}
-
-// Atomically store new_value into *ptr, returning the previous value held in
-// *ptr.  This routine implies no memory barriers.
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  Atomic64 temp, old;
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "lld %1, %4\n"  // old = *ptr
-                       "move %0, %3\n"  // temp = new_value
-                       "scd %0, %2\n"  // *ptr = temp (with atomic check)
-                       "beqz %0, 1b\n"  // start again on atomic error
-                       "nop\n"  // delay slot nop
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
-                       : "r" (new_value), "m" (*ptr)
-                       : "memory");
-
-  return old;
-}
-
-// Atomically increment *ptr by "increment".  Returns the new value of
-// *ptr with the increment applied.  This routine implies no memory barriers.
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  Atomic64 temp, temp2;
-
-  __asm__ __volatile__(".set push\n"
-                       ".set noreorder\n"
-                       "1:\n"
-                       "lld %0, %4\n"  // temp = *ptr
-                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
-                       "scd %1, %2\n"  // *ptr = temp2 (with atomic check)
-                       "beqz %1, 1b\n"  // start again on atomic error
-                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
-                       ".set pop\n"
-                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
-                       : "Ir" (increment), "m" (*ptr)
-                       : "memory");
-  // temp2 now holds the final value.
-  return temp2;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  MemoryBarrier();
-  Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
-  MemoryBarrier();
-  return res;
-}
-
-// "Acquire" operations
-// ensure that no later memory access can be reordered ahead of the operation.
-// "Release" operations ensure that no previous memory access can be reordered
-// after the operation.  "Barrier" operations have both "Acquire" and "Release"
-// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
-// access.
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  MemoryBarrier();
-  return res;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  MemoryBarrier();
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  MemoryBarrier();
-  *ptr = value;
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr;
-  MemoryBarrier();
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-#endif
-
-}  // namespace subtle
-}  // namespace base
-
-#endif  // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
deleted file mode 100644
index c21e96d..0000000
--- a/base/atomicops_internals_x86_gcc.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2006-2008 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 module gets enough CPU information to optimize the
-// atomicops module on x86.
-
-#include <stdint.h>
-#include <string.h>
-
-#include "base/atomicops.h"
-
-// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
-// of the global offset table.  To avoid breaking such executables, this code
-// must preserve that register's value across cpuid instructions.
-//
-// The include guards are the same as in atomicops.h.
-#if defined(__i386__)
-#define cpuid(a, b, c, d, inp) \
-  asm("mov %%ebx, %%edi\n"     \
-      "cpuid\n"                \
-      "xchg %%edi, %%ebx\n"    \
-      : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
-#elif defined(__x86_64__)
-#define cpuid(a, b, c, d, inp) \
-  asm("mov %%rbx, %%rdi\n"     \
-      "cpuid\n"                \
-      "xchg %%rdi, %%rbx\n"    \
-      : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
-#endif
-
-#if defined(cpuid)        // initialize the struct only on x86
-
-// Set the flags so that code will run correctly and conservatively, so even
-// if we haven't been initialized yet, we're probably single threaded, and our
-// default values should hopefully be pretty safe.
-struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
-  false, // bug can't exist before process spawns multiple threads
-  false, // Chrome requires SSE2, but for transition assume not and initialize
-         // this properly.
-  false, // cmpxchg16b isn't present on early AMD64 CPUs.
-};
-
-namespace {
-
-// Initialize the AtomicOps_Internalx86CPUFeatures struct.
-void AtomicOps_Internalx86CPUFeaturesInit() {
-  uint32_t eax;
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-
-  // Get vendor string (issue CPUID with eax = 0)
-  cpuid(eax, ebx, ecx, edx, 0);
-  char vendor[13];
-  memcpy(vendor, &ebx, 4);
-  memcpy(vendor + 4, &edx, 4);
-  memcpy(vendor + 8, &ecx, 4);
-  vendor[12] = 0;
-
-  // get feature flags in ecx/edx, and family/model in eax
-  cpuid(eax, ebx, ecx, edx, 1);
-
-  int family = (eax >> 8) & 0xf;        // family and model fields
-  int model = (eax >> 4) & 0xf;
-  if (family == 0xf) {                  // use extended family and model fields
-    family += (eax >> 20) & 0xff;
-    model += ((eax >> 16) & 0xf) << 4;
-  }
-
-  // Opteron Rev E has a bug in which on very rare occasions a locked
-  // instruction doesn't act as a read-acquire barrier if followed by a
-  // non-locked read-modify-write instruction.  Rev F has this bug in
-  // pre-release versions, but not in versions released to customers,
-  // so we test only for Rev E, which is family 15, model 32..63 inclusive.
-  if (strcmp(vendor, "AuthenticAMD") == 0 &&       // AMD
-      family == 15 &&
-      32 <= model && model <= 63) {
-    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
-  } else {
-    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
-  }
-
-  // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
-  AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
-
-  // ecx bit 13 indicates whether the cmpxchg16b instruction is supported
-  AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1);
-}
-
-class AtomicOpsx86Initializer {
- public:
-  AtomicOpsx86Initializer() {
-    AtomicOps_Internalx86CPUFeaturesInit();
-  }
-};
-
-// A global to get use initialized on startup via static initialization :/
-AtomicOpsx86Initializer g_initer;
-
-}  // namespace
-
-#endif  // if x86
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
deleted file mode 100644
index f0d2242..0000000
--- a/base/atomicops_internals_x86_gcc.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file is an internal atomic implementation, use base/atomicops.h instead.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
-#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
-
-#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
-
-namespace base {
-namespace subtle {
-
-// 32-bit low-level operations on any platform.
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
-                                         Atomic32 old_value,
-                                         Atomic32 new_value) {
-  Atomic32 prev;
-  __asm__ __volatile__("lock; cmpxchgl %1,%2"
-                       : "=a" (prev)
-                       : "q" (new_value), "m" (*ptr), "0" (old_value)
-                       : "memory");
-  return prev;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
-                                         Atomic32 new_value) {
-  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
-                       : "=r" (new_value)
-                       : "m" (*ptr), "0" (new_value)
-                       : "memory");
-  return new_value;  // Now it's the previous value.
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
-                                          Atomic32 increment) {
-  Atomic32 temp = increment;
-  __asm__ __volatile__("lock; xaddl %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now holds the old value of *ptr
-  return temp + increment;
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
-                                        Atomic32 increment) {
-  Atomic32 temp = increment;
-  __asm__ __volatile__("lock; xaddl %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now holds the old value of *ptr
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return temp + increment;
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return x;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
-                                       Atomic32 old_value,
-                                       Atomic32 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-}
-
-inline void MemoryBarrier() {
-  __asm__ __volatile__("mfence" : : : "memory");
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  ATOMICOPS_COMPILER_BARRIER();
-  *ptr = value; // An x86 store acts as a release barrier.
-  // See comments in Atomic64 version of Release_Store(), below.
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
-  return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
-  // See comments in Atomic64 version of Release_Store(), below.
-  ATOMICOPS_COMPILER_BARRIER();
-  return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-#if defined(__x86_64__)
-
-// 64-bit low-level operations on 64-bit platform.
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
-                                         Atomic64 old_value,
-                                         Atomic64 new_value) {
-  Atomic64 prev;
-  __asm__ __volatile__("lock; cmpxchgq %1,%2"
-                       : "=a" (prev)
-                       : "q" (new_value), "m" (*ptr), "0" (old_value)
-                       : "memory");
-  return prev;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
-                                         Atomic64 new_value) {
-  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
-                       : "=r" (new_value)
-                       : "m" (*ptr), "0" (new_value)
-                       : "memory");
-  return new_value;  // Now it's the previous value.
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
-                                          Atomic64 increment) {
-  Atomic64 temp = increment;
-  __asm__ __volatile__("lock; xaddq %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now contains the previous value of *ptr
-  return temp + increment;
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
-                                        Atomic64 increment) {
-  Atomic64 temp = increment;
-  __asm__ __volatile__("lock; xaddq %0,%1"
-                       : "+r" (temp), "+m" (*ptr)
-                       : : "memory");
-  // temp now contains the previous value of *ptr
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return temp + increment;
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
-  *ptr = value;
-  MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-  ATOMICOPS_COMPILER_BARRIER();
-
-  *ptr = value; // An x86 store acts as a release barrier
-                // for current AMD/Intel chips as of Jan 2008.
-                // See also Acquire_Load(), below.
-
-  // When new chips come out, check:
-  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
-  //  System Programming Guide, Chatper 7: Multiple-processor management,
-  //  Section 7.2, Memory Ordering.
-  // Last seen at:
-  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
-  //
-  // x86 stores/loads fail to act as barriers for a few instructions (clflush
-  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
-  // not generated by the compiler, and are rare.  Users of these instructions
-  // need to know about cache behaviour in any case since all of these involve
-  // either flushing cache lines or non-temporal cache hints.
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
-  return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-  Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
-                         // for current AMD/Intel chips as of Jan 2008.
-                         // See also Release_Store(), above.
-  ATOMICOPS_COMPILER_BARRIER();
-  return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
-  MemoryBarrier();
-  return *ptr;
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
-    __asm__ __volatile__("lfence" : : : "memory");
-  }
-  return x;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
-                                       Atomic64 old_value,
-                                       Atomic64 new_value) {
-  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-#endif  // defined(__x86_64__)
-
-}  // namespace subtle
-}  // namespace base
-
-#undef ATOMICOPS_COMPILER_BARRIER
-
-#endif  // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/base.isolate b/base/base.isolate
index c7ba651..948c600 100644
--- a/base/base.isolate
+++ b/base/base.isolate
@@ -36,7 +36,9 @@
     ['OS=="win" and asan==1 and component=="shared_library"', {
       'variables': {
         'files': [
-          '../third_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll',
+          # We only need x.y.z/lib/windows/clang_rt.asan_dynamic-i386.dll,
+          # but since the version (x.y.z) changes, just grab the whole dir.
+          '../third_party/llvm-build/Release+Asserts/lib/clang/',
         ],
       },
     }],
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
index 9864eb3..a9d01f2 100644
--- a/base/base_paths_mac.mm
+++ b/base/base_paths_mac.mm
@@ -29,8 +29,8 @@
   _NSGetExecutablePath(NULL, &executable_length);
   DCHECK_GT(executable_length, 1u);
   std::string executable_path;
-  int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
-                                &executable_length);
+  int rv = _NSGetExecutablePath(
+      base::WriteInto(&executable_path, executable_length), &executable_length);
   DCHECK_EQ(rv, 0);
 
   // _NSGetExecutablePath may return paths containing ./ or ../ which makes
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
index 4ecb59d..58f925f 100644
--- a/base/base_paths_win.cc
+++ b/base/base_paths_win.cc
@@ -32,14 +32,16 @@
   FilePath cur;
   switch (key) {
     case base::FILE_EXE:
-      GetModuleFileName(NULL, system_buffer, MAX_PATH);
+      if (GetModuleFileName(NULL, system_buffer, MAX_PATH) == 0)
+        return false;
       cur = FilePath(system_buffer);
       break;
     case base::FILE_MODULE: {
       // the resource containing module is assumed to be the one that
       // this code lives in, whether that's a dll or exe
       HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
-      GetModuleFileName(this_module, system_buffer, MAX_PATH);
+      if (GetModuleFileName(this_module, system_buffer, MAX_PATH) == 0)
+        return false;
       cur = FilePath(system_buffer);
       break;
     }
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 3076540..6d517e5 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -67,6 +67,11 @@
 // chrome://profiler.
 const char kProfilerTimingDisabledValue[]   = "0";
 
+#if defined(OS_WIN)
+// Disables the USB keyboard detection for blocking the OSK on Win8+.
+const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
+#endif
+
 #if defined(OS_POSIX)
 // Used for turning on Breakpad crash reporting in a debug environment where
 // crash reporting is typically compiled but disabled.
diff --git a/base/base_switches.h b/base/base_switches.h
index c579f6a..bbd590b 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -27,6 +27,10 @@
 extern const char kVModule[];
 extern const char kWaitForDebugger[];
 
+#if defined(OS_WIN)
+extern const char kDisableUsbKeyboardDetect[];
+#endif
+
 #if defined(OS_POSIX)
 extern const char kEnableCrashReporterForTesting[];
 #endif
diff --git a/base/basictypes.h b/base/basictypes.h
index bf75e67..d71abd9 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -16,7 +16,7 @@
 #include <stdint.h>  // For intptr_t.
 
 #include "base/macros.h"
-#include "base/port.h"  // Types that only need exist on certain systems.
+#include "build/build_config.h"
 
 // DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
 typedef int8_t int8;
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 63297dc..66dc80d 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -140,7 +140,7 @@
 // Annotate a function indicating the caller must examine the return value.
 // Use like:
 //   int foo() WARN_UNUSED_RESULT;
-// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
 #if defined(COMPILER_GCC)
 #define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 #else
diff --git a/base/containers/scoped_ptr_map.h b/base/containers/scoped_ptr_map.h
new file mode 100644
index 0000000..a4605e3
--- /dev/null
+++ b/base/containers/scoped_ptr_map.h
@@ -0,0 +1,144 @@
+// 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_CONTAINERS_SCOPED_PTR_MAP_H_
+#define BASE_CONTAINERS_SCOPED_PTR_MAP_H_
+
+#include <functional>
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/move.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+// ScopedPtrMap provides a std::map that supports scoped_ptr values. It ensures
+// that the map's values are properly deleted when removed from the map, or when
+// the map is destroyed.
+//
+// |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
+// std::map in C++11.
+template <class Key, class ScopedPtr, class Compare = std::less<Key>>
+class ScopedPtrMap {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)
+
+  using Container = std::map<Key, typename ScopedPtr::element_type*, Compare>;
+
+ public:
+  using allocator_type = typename Container::allocator_type;
+  using size_type = typename Container::size_type;
+  using difference_type = typename Container::difference_type;
+  using reference = typename Container::reference;
+  using const_reference = typename Container::const_reference;
+  using key_type = typename Container::key_type;
+  using mapped_type = ScopedPtr;
+  using key_compare = typename Container::key_compare;
+  using const_iterator = typename Container::const_iterator;
+  using const_reverse_iterator = typename Container::const_reverse_iterator;
+
+  ScopedPtrMap() {}
+  ~ScopedPtrMap() { clear(); }
+  ScopedPtrMap(ScopedPtrMap<Key, ScopedPtr>&& other) { swap(other); }
+
+  ScopedPtrMap& operator=(ScopedPtrMap<Key, ScopedPtr>&& rhs) {
+    swap(rhs);
+    return *this;
+  }
+
+  const_iterator find(const Key& k) const { return data_.find(k); }
+  size_type count(const Key& k) const { return data_.count(k); }
+
+  bool empty() const { return data_.empty(); }
+  size_t size() const { return data_.size(); }
+
+  const_reverse_iterator rbegin() const { return data_.rbegin(); }
+  const_reverse_iterator rend() const { return data_.rend(); }
+
+  const_iterator begin() const { return data_.begin(); }
+  const_iterator end() const { return data_.end(); }
+
+  void swap(ScopedPtrMap<Key, ScopedPtr>& other) { data_.swap(other.data_); }
+
+  void clear() { STLDeleteValues(&data_); }
+
+  // Inserts |val| into the map, associated with |key|.
+  std::pair<const_iterator, bool> insert(const Key& key, ScopedPtr val) {
+    auto result = data_.insert(std::make_pair(key, val.get()));
+    if (result.second)
+      ignore_result(val.release());
+    return result;
+  }
+
+  // Inserts |val| into the map, associated with |key|. Overwrites any existing
+  // element at |key|.
+  void set(const Key& key, ScopedPtr val) {
+    typename ScopedPtr::element_type*& val_ref = data_[key];
+    delete val_ref;
+    val_ref = val.release();
+  }
+
+  void erase(const_iterator position) {
+    DCHECK(position != end());
+    delete position->second;
+    // Key-based lookup (cannot use const_iterator overload in C++03 library).
+    data_.erase(position->first);
+  }
+
+  size_type erase(const Key& k) {
+    typename Container::iterator it = data_.find(k);
+    if (it == end())
+      return 0;
+
+    delete it->second;
+    data_.erase(it);
+    return 1;
+  }
+
+  void erase(const_iterator first, const_iterator last) {
+    STLDeleteContainerPairSecondPointers(first, last);
+    // Need non-const iterators as required by the C++03 library.
+    data_.erase(ConstIteratorToIterator(first), ConstIteratorToIterator(last));
+  }
+
+  // Like |erase()|, but returns the element instead of deleting it.
+  ScopedPtr take_and_erase(const_iterator position) {
+    DCHECK(position != end());
+    if (position == end())
+      return ScopedPtr();
+
+    ScopedPtr ret(position->second);
+    // Key-based lookup (cannot use const_iterator overload in C++03 library).
+    data_.erase(position->first);
+    return ret.Pass();
+  }
+
+  // Like |erase()|, but returns the element instead of deleting it.
+  ScopedPtr take_and_erase(const Key& k) {
+    typename Container::iterator it = data_.find(k);
+    if (it == end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    data_.erase(it);
+    return ret.Pass();
+  }
+
+ private:
+  Container data_;
+
+  typename Container::iterator ConstIteratorToIterator(const_iterator it) {
+    // This is the only way to convert a const iterator to a non-const iterator
+    // in C++03 (get the key and do the lookup again).
+    if (it == data_.end())
+      return data_.end();
+    return data_.find(it->first);
+  };
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_SCOPED_PTR_MAP_H_
diff --git a/base/containers/scoped_ptr_map_unittest.cc b/base/containers/scoped_ptr_map_unittest.cc
new file mode 100644
index 0000000..46843b3
--- /dev/null
+++ b/base/containers/scoped_ptr_map_unittest.cc
@@ -0,0 +1,240 @@
+// 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/containers/scoped_ptr_map.h"
+
+#include <functional>
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// A ScopedDestroyer sets a Boolean to true upon destruction.
+class ScopedDestroyer {
+ public:
+  ScopedDestroyer(bool* destroyed) : destroyed_(destroyed) {
+    *destroyed_ = false;
+  }
+
+  ~ScopedDestroyer() { *destroyed_ = true; }
+
+ private:
+  bool* destroyed_;
+};
+
+TEST(ScopedPtrMapTest, Insert) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+    // Insert to new key.
+    ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
+    EXPECT_FALSE(destroyed1);
+    EXPECT_TRUE(scoped_map.insert(0, make_scoped_ptr(elem1)).second);
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed1);
+
+    // Insert to existing key.
+    ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
+    EXPECT_FALSE(destroyed2);
+    EXPECT_FALSE(scoped_map.insert(0, make_scoped_ptr(elem2)).second);
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+
+    EXPECT_FALSE(destroyed1);
+    EXPECT_TRUE(destroyed2);
+  }
+  EXPECT_TRUE(destroyed1);
+}
+
+TEST(ScopedPtrMapTest, Set) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+    // Set a new key.
+    ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
+    EXPECT_FALSE(destroyed1);
+    scoped_map.set(0, make_scoped_ptr(elem1));
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed1);
+
+    // Set to replace an existing key.
+    ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
+    EXPECT_FALSE(destroyed2);
+    scoped_map.set(0, make_scoped_ptr(elem2));
+    EXPECT_EQ(elem2, scoped_map.find(0)->second);
+
+    EXPECT_TRUE(destroyed1);
+    EXPECT_FALSE(destroyed2);
+  }
+  EXPECT_TRUE(destroyed1);
+  EXPECT_TRUE(destroyed2);
+}
+
+TEST(ScopedPtrMapTest, EraseIterator) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  scoped_map.erase(scoped_map.find(0));
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, EraseKey) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  EXPECT_EQ(1u, scoped_map.erase(0));
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+
+  // Test erase of a non-existent key.
+  EXPECT_EQ(0u, scoped_map.erase(7));
+}
+
+TEST(ScopedPtrMapTest, EraseRange) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed1)));
+  EXPECT_FALSE(destroyed1);
+
+  scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed2)));
+  EXPECT_FALSE(destroyed2);
+
+  scoped_map.erase(scoped_map.find(0), scoped_map.end());
+  EXPECT_TRUE(destroyed1);
+  EXPECT_TRUE(destroyed2);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, TakeAndErase) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+  scoped_map.insert(0, make_scoped_ptr(elem));
+  EXPECT_EQ(elem, scoped_map.find(0)->second);
+  EXPECT_FALSE(destroyed);
+  scoped_ptr<ScopedDestroyer> object = scoped_map.take_and_erase(0);
+  EXPECT_EQ(elem, object.get());
+  EXPECT_FALSE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+  object.reset();
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, Clear) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  scoped_map.clear();
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, Compare) {
+  // Construct a ScopedPtrMap with a custom comparison function.
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>, std::greater<int>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+
+  auto it = scoped_map.begin();
+  EXPECT_EQ(1, it->first);
+  ++it;
+  EXPECT_EQ(0, it->first);
+}
+
+TEST(ScopedPtrMapTest, Scope) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, MoveConstruct) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+    scoped_map.insert(0, make_scoped_ptr(elem));
+    EXPECT_EQ(elem, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed);
+    EXPECT_FALSE(scoped_map.empty());
+
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_copy(
+        scoped_map.Pass());
+    EXPECT_TRUE(scoped_map.empty());
+    EXPECT_FALSE(scoped_map_copy.empty());
+    EXPECT_EQ(elem, scoped_map_copy.find(0)->second);
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, MoveAssign) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+    scoped_map.insert(0, make_scoped_ptr(elem));
+    EXPECT_EQ(elem, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed);
+    EXPECT_FALSE(scoped_map.empty());
+
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_assign;
+    scoped_map_assign = scoped_map.Pass();
+    EXPECT_TRUE(scoped_map.empty());
+    EXPECT_FALSE(scoped_map_assign.empty());
+    EXPECT_EQ(elem, scoped_map_assign.find(0)->second);
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+template <typename Key, typename ScopedPtr>
+ScopedPtrMap<Key, ScopedPtr> PassThru(ScopedPtrMap<Key, ScopedPtr> scoper) {
+  return scoper;
+}
+
+TEST(ScopedPtrMapTest, Passed) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+  scoped_map.insert(0, make_scoped_ptr(elem));
+  EXPECT_EQ(elem, scoped_map.find(0)->second);
+  EXPECT_FALSE(destroyed);
+
+  base::Callback<ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>>(void)>
+      callback = base::Bind(&PassThru<int, scoped_ptr<ScopedDestroyer>>,
+                            base::Passed(&scoped_map));
+  EXPECT_TRUE(scoped_map.empty());
+  EXPECT_FALSE(destroyed);
+
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> result = callback.Run();
+  EXPECT_TRUE(scoped_map.empty());
+  EXPECT_EQ(elem, result.find(0)->second);
+  EXPECT_FALSE(destroyed);
+
+  result.clear();
+  EXPECT_TRUE(destroyed);
+};
+
+}  // namespace
+}  // namespace base
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
index f9b4449..058b476 100644
--- a/base/debug/crash_logging.cc
+++ b/base/debug/crash_logging.cc
@@ -119,7 +119,7 @@
       hex_backtrace.push_back(s);
     }
 
-    value = JoinString(hex_backtrace, ' ');
+    value = base::JoinString(hex_backtrace, " ");
 
     // Warn if this exceeds the breakpad limits.
     DCHECK_LE(value.length(), kBreakpadValueMax);
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
index ed553cd..924c769 100644
--- a/base/debug/profiler.cc
+++ b/base/debug/profiler.cc
@@ -7,8 +7,8 @@
 #include <string>
 
 #include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
 
 #if defined(OS_WIN)
 #include "base/win/pe_image.h"
@@ -30,8 +30,8 @@
 void StartProfiling(const std::string& name) {
   ++profile_count;
   std::string full_name(name);
-  std::string pid = StringPrintf("%d", GetCurrentProcId());
-  std::string count = StringPrintf("%d", profile_count);
+  std::string pid = IntToString(GetCurrentProcId());
+  std::string count = IntToString(profile_count);
   ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
   ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
   ProfilerStart(full_name.c_str());
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index 76cb524..8749bed 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -788,7 +788,8 @@
 
   // Handle negative numbers (only for base 10).
   if (i < 0 && base == 10) {
-    j = -i;
+    // This does "j = -i" while avoiding integer overflow.
+    j = static_cast<uintptr_t>(-(i + 1)) + 1;
 
     // Make sure we can write the '-' character.
     if (++n > sz) {
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
index 19df8cb..b74d390 100644
--- a/base/debug/task_annotator.cc
+++ b/base/debug/task_annotator.cc
@@ -26,7 +26,6 @@
 }
 
 void TaskAnnotator::RunTask(const char* queue_function,
-                            const char* run_function,
                             const PendingTask& pending_task) {
   tracked_objects::TaskStopwatch stopwatch;
   stopwatch.Start();
@@ -39,18 +38,6 @@
                         "queue_duration",
                         queue_duration.InMilliseconds());
 
-  // When tracing memory for posted tasks it's more valuable to attribute the
-  // memory allocations to the source function than generically to the task
-  // runner.
-  TRACE_EVENT_WITH_MEMORY_TAG2(
-      "toplevel",
-      run_function,
-      pending_task.posted_from.function_name(),  // Name for memory tracking.
-      "src_file",
-      pending_task.posted_from.file_name(),
-      "src_func",
-      pending_task.posted_from.function_name());
-
   // Before running the task, store the program counter where it was posted
   // and deliberately alias it to ensure it is on the stack if the task
   // crashes. Be careful not to assume that the variable itself will have the
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
index aa5f17b..74068d9 100644
--- a/base/debug/task_annotator.h
+++ b/base/debug/task_annotator.h
@@ -25,11 +25,8 @@
                     const PendingTask& pending_task);
 
   // Run a previously queued task. |queue_function| should match what was
-  // passed into |DidQueueTask| for this task. |run_function| is used as the
-  // name for the trace event that surrounds the task's execution.
-  void RunTask(const char* queue_function,
-               const char* run_function,
-               const PendingTask& pending_task);
+  // passed into |DidQueueTask| for this task.
+  void RunTask(const char* queue_function, const PendingTask& pending_task);
 
  private:
   // Creates a process-wide unique ID to represent this task in trace events.
@@ -40,6 +37,13 @@
   DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
 };
 
+#define TRACE_TASK_EXECUTION(run_function, task)                          \
+  TRACE_EVENT_WITH_MEMORY_TAG2(                                           \
+      "toplevel", (run_function),                                         \
+      (task).posted_from.function_name(), /* Name for memory tracking. */ \
+      "src_file", (task).posted_from.file_name(), "src_func",             \
+      (task).posted_from.function_name());
+
 }  // namespace debug
 }  // namespace base
 
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc
index ddffc21..9f5c442 100644
--- a/base/debug/task_annotator_unittest.cc
+++ b/base/debug/task_annotator_unittest.cc
@@ -24,8 +24,7 @@
   TaskAnnotator annotator;
   annotator.DidQueueTask("TaskAnnotatorTest::Queue", pending_task);
   EXPECT_EQ(0, result);
-  annotator.RunTask(
-      "TaskAnnotatorTest::Queue", "TaskAnnotatorTest::Run", pending_task);
+  annotator.RunTask("TaskAnnotatorTest::Queue", pending_task);
   EXPECT_EQ(123, result);
 }
 
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
index 9b10d04..c5e9859 100644
--- a/base/file_version_info_unittest.cc
+++ b/base/file_version_info_unittest.cc
@@ -32,53 +32,49 @@
 
 #if defined(OS_WIN)
 TEST(FileVersionInfoTest, HardCodedProperties) {
-  const wchar_t* kDLLNames[] = {
-    L"FileVersionInfoTest1.dll"
-  };
+  const wchar_t kDLLName[] = {L"FileVersionInfoTest1.dll"};
 
-  const wchar_t* kExpectedValues[1][15] = {
+  const wchar_t* const kExpectedValues[15] = {
       // FileVersionInfoTest.dll
-      L"Goooooogle",                      // company_name
-      L"Google",                          // company_short_name
-      L"This is the product name",        // product_name
-      L"This is the product short name",  // product_short_name
-      L"The Internal Name",               // internal_name
-      L"4.3.2.1",                         // product_version
-      L"Private build property",          // private_build
-      L"Special build property",          // special_build
+      L"Goooooogle",                                  // company_name
+      L"Google",                                      // company_short_name
+      L"This is the product name",                    // product_name
+      L"This is the product short name",              // product_short_name
+      L"The Internal Name",                           // internal_name
+      L"4.3.2.1",                                     // product_version
+      L"Private build property",                      // private_build
+      L"Special build property",                      // special_build
       L"This is a particularly interesting comment",  // comments
-      L"This is the original filename",   // original_filename
-      L"This is my file description",     // file_description
-      L"1.2.3.4",                         // file_version
-      L"This is the legal copyright",     // legal_copyright
-      L"This is the legal trademarks",    // legal_trademarks
-      L"This is the last change",         // last_change
+      L"This is the original filename",               // original_filename
+      L"This is my file description",                 // file_description
+      L"1.2.3.4",                                     // file_version
+      L"This is the legal copyright",                 // legal_copyright
+      L"This is the legal trademarks",                // legal_trademarks
+      L"This is the last change",                     // last_change
   };
 
-  for (int i = 0; i < arraysize(kDLLNames); ++i) {
-    FilePath dll_path = GetTestDataPath();
-    dll_path = dll_path.Append(kDLLNames[i]);
+  FilePath dll_path = GetTestDataPath();
+  dll_path = dll_path.Append(kDLLName);
 
-    scoped_ptr<FileVersionInfo> version_info(
-        FileVersionInfo::CreateFileVersionInfo(dll_path));
+  scoped_ptr<FileVersionInfo> version_info(
+      FileVersionInfo::CreateFileVersionInfo(dll_path));
 
-    int j = 0;
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_name());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_short_name());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_name());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_short_name());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->internal_name());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_version());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->private_build());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->special_build());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->comments());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->original_filename());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_description());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_version());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_copyright());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_trademarks());
-    EXPECT_EQ(kExpectedValues[i][j++], version_info->last_change());
-  }
+  int j = 0;
+  EXPECT_EQ(kExpectedValues[j++], version_info->company_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->company_short_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_short_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->internal_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_version());
+  EXPECT_EQ(kExpectedValues[j++], version_info->private_build());
+  EXPECT_EQ(kExpectedValues[j++], version_info->special_build());
+  EXPECT_EQ(kExpectedValues[j++], version_info->comments());
+  EXPECT_EQ(kExpectedValues[j++], version_info->original_filename());
+  EXPECT_EQ(kExpectedValues[j++], version_info->file_description());
+  EXPECT_EQ(kExpectedValues[j++], version_info->file_version());
+  EXPECT_EQ(kExpectedValues[j++], version_info->legal_copyright());
+  EXPECT_EQ(kExpectedValues[j++], version_info->legal_trademarks());
+  EXPECT_EQ(kExpectedValues[j++], version_info->last_change());
 }
 #endif
 
diff --git a/base/files/file.cc b/base/files/file.cc
index 58f80c5..9a4ddb1 100644
--- a/base/files/file.cc
+++ b/base/files/file.cc
@@ -52,22 +52,30 @@
 
 File::File(RValue other)
     : file_(other.object->TakePlatformFile()),
-      path_(other.object->path_),
+      tracing_path_(other.object->tracing_path_),
       error_details_(other.object->error_details()),
       created_(other.object->created()),
-      async_(other.object->async_) {
-}
+      async_(other.object->async_) {}
 
 File::~File() {
   // Go through the AssertIOAllowed logic.
   Close();
 }
 
+// static
+File File::CreateForAsyncHandle(PlatformFile platform_file) {
+  File file(platform_file);
+  // It would be nice if we could validate that |platform_file| was opened with
+  // FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible.
+  file.async_ = true;
+  return file.Pass();
+}
+
 File& File::operator=(RValue other) {
   if (this != other.object) {
     Close();
     SetPlatformFile(other.object->TakePlatformFile());
-    path_ = other.object->path_;
+    tracing_path_ = other.object->tracing_path_;
     error_details_ = other.object->error_details();
     created_ = other.object->created();
     async_ = other.object->async_;
@@ -81,9 +89,10 @@
     error_details_ = FILE_ERROR_ACCESS_DENIED;
     return;
   }
-  path_ = path;
+  if (FileTracing::IsCategoryEnabled())
+    tracing_path_ = path;
   SCOPED_FILE_TRACE("Initialize");
-  DoInitialize(flags);
+  DoInitialize(path, flags);
 }
 #endif
 
diff --git a/base/files/file.h b/base/files/file.h
index b21b159..cba4353 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -176,6 +176,9 @@
 
   ~File();
 
+  // Takes ownership of |platform_file|.
+  static File CreateForAsyncHandle(PlatformFile platform_file);
+
   // Move operator= for C++03 move emulation of this type.
   File& operator=(RValue other);
 
@@ -352,9 +355,9 @@
   };
 #endif
 
-  // Creates or opens the given file. Only called if |path_| has no
+  // Creates or opens the given file. Only called if |path| has no
   // traversal ('..') components.
-  void DoInitialize(uint32 flags);
+  void DoInitialize(const FilePath& path, uint32 flags);
 
   // TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
   // cf. issue 473337.
@@ -368,8 +371,9 @@
   MemoryCheckingScopedFD file_;
 #endif
 
-  // Path that |Initialize()| was called with. Only set if safe (i.e. no '..').
-  FilePath path_;
+  // A path to use for tracing purposes. Set if file tracing is enabled during
+  // |Initialize()|.
+  FilePath tracing_path_;
 
   // Object tied to the lifetime of |this| that enables/disables tracing.
   FileTracing::ScopedEnabler trace_enabler_;
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index 931d154..ae41a46 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -43,10 +43,10 @@
 FileEnumerator::FileEnumerator(const FilePath& root_path,
                                bool recursive,
                                int file_type)
-    : recursive_(recursive),
-      file_type_(file_type),
-      has_find_data_(false),
-      find_handle_(INVALID_HANDLE_VALUE) {
+    : has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE),
+      recursive_(recursive),
+      file_type_(file_type) {
   // INCLUDE_DOT_DOT must not be specified if recursive.
   DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
   memset(&find_data_, 0, sizeof(find_data_));
@@ -57,11 +57,11 @@
                                bool recursive,
                                int file_type,
                                const FilePath::StringType& pattern)
-    : recursive_(recursive),
+    : has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE),
+      recursive_(recursive),
       file_type_(file_type),
-      has_find_data_(false),
-      pattern_(pattern),
-      find_handle_(INVALID_HANDLE_VALUE) {
+      pattern_(pattern) {
   // INCLUDE_DOT_DOT must not be specified if recursive.
   DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
   memset(&find_data_, 0, sizeof(find_data_));
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
index de8927a..10dcf94 100644
--- a/base/files/file_path.cc
+++ b/base/files/file_path.cc
@@ -10,9 +10,6 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/pickle.h"
-
-// These includes are just for the *Hack functions, and should be removed
-// when those functions are removed.
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
@@ -31,7 +28,8 @@
 
 namespace base {
 
-typedef FilePath::StringType StringType;
+using StringType = FilePath::StringType;
+using StringPieceType = FilePath::StringPieceType;
 
 namespace {
 
@@ -45,7 +43,7 @@
 // otherwise returns npos.  This can only be true on Windows, when a pathname
 // begins with a letter followed by a colon.  On other platforms, this always
 // returns npos.
-StringType::size_type FindDriveLetter(const StringType& path) {
+StringPieceType::size_type FindDriveLetter(StringPieceType path) {
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
   // This is dependent on an ASCII-based character set, but that's a
   // reasonable assumption.  iswalpha can be too inclusive here.
@@ -59,26 +57,25 @@
 }
 
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
-bool EqualDriveLetterCaseInsensitive(const StringType& a,
-                                     const StringType& b) {
+bool EqualDriveLetterCaseInsensitive(StringPieceType a, StringPieceType b) {
   size_t a_letter_pos = FindDriveLetter(a);
   size_t b_letter_pos = FindDriveLetter(b);
 
   if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
     return a == b;
 
-  StringType a_letter(a.substr(0, a_letter_pos + 1));
-  StringType b_letter(b.substr(0, b_letter_pos + 1));
-  if (!StartsWith(a_letter, b_letter, false))
+  StringPieceType a_letter(a.substr(0, a_letter_pos + 1));
+  StringPieceType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, CompareCase::INSENSITIVE_ASCII))
     return false;
 
-  StringType a_rest(a.substr(a_letter_pos + 1));
-  StringType b_rest(b.substr(b_letter_pos + 1));
+  StringPieceType a_rest(a.substr(a_letter_pos + 1));
+  StringPieceType b_rest(b.substr(b_letter_pos + 1));
   return a_rest == b_rest;
 }
 #endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
 
-bool IsPathAbsolute(const StringType& path) {
+bool IsPathAbsolute(StringPieceType path) {
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
   StringType::size_type letter = FindDriveLetter(path);
   if (letter != StringType::npos) {
@@ -177,7 +174,8 @@
 FilePath::FilePath(const FilePath& that) : path_(that.path_) {
 }
 
-FilePath::FilePath(const StringType& path) : path_(path) {
+FilePath::FilePath(StringPieceType path) {
+  path.CopyToString(&path_);
   StringType::size_type nul_pos = path_.find(kStringTerminator);
   if (nul_pos != StringType::npos)
     path_.erase(nul_pos, StringType::npos);
@@ -279,7 +277,7 @@
   // never case sensitive.
   if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
       (FindDriveLetter(*child_comp) != StringType::npos)) {
-    if (!StartsWith(*parent_comp, *child_comp, false))
+    if (!StartsWith(*parent_comp, *child_comp, CompareCase::INSENSITIVE_ASCII))
       return false;
     ++parent_comp;
     ++child_comp;
@@ -404,7 +402,7 @@
   return FilePath(path_.substr(0, dot));
 }
 
-FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
+FilePath FilePath::InsertBeforeExtension(StringPieceType suffix) const {
   if (suffix.empty())
     return FilePath(path_);
 
@@ -413,27 +411,27 @@
 
   StringType ext = Extension();
   StringType ret = RemoveExtension().value();
-  ret.append(suffix);
+  suffix.AppendToString(&ret);
   ret.append(ext);
   return FilePath(ret);
 }
 
-FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix)
-    const {
+FilePath FilePath::InsertBeforeExtensionASCII(StringPiece suffix) const {
   DCHECK(IsStringASCII(suffix));
 #if defined(OS_WIN)
-  return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
+  return InsertBeforeExtension(ASCIIToUTF16(suffix));
 #elif defined(OS_POSIX)
-  return InsertBeforeExtension(suffix.as_string());
+  return InsertBeforeExtension(suffix);
 #endif
 }
 
-FilePath FilePath::AddExtension(const StringType& extension) const {
+FilePath FilePath::AddExtension(StringPieceType extension) const {
   if (IsEmptyOrSpecialCase(BaseName().value()))
     return FilePath();
 
   // If the new extension is "" or ".", then just return the current FilePath.
-  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+  if (extension.empty() ||
+      (extension.size() == 1 && extension[0] == kExtensionSeparator))
     return *this;
 
   StringType str = path_;
@@ -441,27 +439,28 @@
       *(str.end() - 1) != kExtensionSeparator) {
     str.append(1, kExtensionSeparator);
   }
-  str.append(extension);
+  extension.AppendToString(&str);
   return FilePath(str);
 }
 
-FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+FilePath FilePath::ReplaceExtension(StringPieceType extension) const {
   if (IsEmptyOrSpecialCase(BaseName().value()))
     return FilePath();
 
   FilePath no_ext = RemoveExtension();
   // If the new extension is "" or ".", then just remove the current extension.
-  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+  if (extension.empty() ||
+      (extension.size() == 1 && extension[0] == kExtensionSeparator))
     return no_ext;
 
   StringType str = no_ext.value();
   if (extension[0] != kExtensionSeparator)
     str.append(1, kExtensionSeparator);
-  str.append(extension);
+  extension.AppendToString(&str);
   return FilePath(str);
 }
 
-bool FilePath::MatchesExtension(const StringType& extension) const {
+bool FilePath::MatchesExtension(StringPieceType extension) const {
   DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
 
   StringType current_extension = Extension();
@@ -472,17 +471,17 @@
   return FilePath::CompareEqualIgnoreCase(extension, current_extension);
 }
 
-FilePath FilePath::Append(const StringType& component) const {
-  const StringType* appended = &component;
+FilePath FilePath::Append(StringPieceType component) const {
+  StringPieceType appended = component;
   StringType without_nuls;
 
   StringType::size_type nul_pos = component.find(kStringTerminator);
-  if (nul_pos != StringType::npos) {
-    without_nuls = component.substr(0, nul_pos);
-    appended = &without_nuls;
+  if (nul_pos != StringPieceType::npos) {
+    component.substr(0, nul_pos).CopyToString(&without_nuls);
+    appended = StringPieceType(without_nuls);
   }
 
-  DCHECK(!IsPathAbsolute(*appended));
+  DCHECK(!IsPathAbsolute(appended));
 
   if (path_.compare(kCurrentDirectory) == 0) {
     // Append normally doesn't do any normalization, but as a special case,
@@ -492,7 +491,7 @@
     // it's likely in practice to wind up with FilePath objects containing
     // only kCurrentDirectory when calling DirName on a single relative path
     // component.
-    return FilePath(*appended);
+    return FilePath(appended);
   }
 
   FilePath new_path(path_);
@@ -501,7 +500,7 @@
   // Don't append a separator if the path is empty (indicating the current
   // directory) or if the path component is empty (indicating nothing to
   // append).
-  if (appended->length() > 0 && new_path.path_.length() > 0) {
+  if (appended.length() > 0 && new_path.path_.length() > 0) {
     // Don't append a separator if the path still ends with a trailing
     // separator after stripping (indicating the root directory).
     if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
@@ -512,7 +511,7 @@
     }
   }
 
-  new_path.path_.append(*appended);
+  appended.AppendToString(&new_path.path_);
   return new_path;
 }
 
@@ -520,12 +519,12 @@
   return Append(component.value());
 }
 
-FilePath FilePath::AppendASCII(const StringPiece& component) const {
+FilePath FilePath::AppendASCII(StringPiece component) const {
   DCHECK(base::IsStringASCII(component));
 #if defined(OS_WIN)
-  return Append(ASCIIToUTF16(component.as_string()));
+  return Append(ASCIIToUTF16(component));
 #elif defined(OS_POSIX)
-  return Append(component.as_string());
+  return Append(component);
 #endif
 }
 
@@ -680,17 +679,17 @@
 }
 
 #if defined(OS_WIN)
-// Windows specific implementation of file string comparisons
+// Windows specific implementation of file string comparisons.
 
-int FilePath::CompareIgnoreCase(const StringType& string1,
-                                const StringType& string2) {
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType string2) {
   // Perform character-wise upper case comparison rather than using the
   // fully Unicode-aware CompareString(). For details see:
   // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx
-  StringType::const_iterator i1 = string1.begin();
-  StringType::const_iterator i2 = string2.begin();
-  StringType::const_iterator string1end = string1.end();
-  StringType::const_iterator string2end = string2.end();
+  StringPieceType::const_iterator i1 = string1.begin();
+  StringPieceType::const_iterator i2 = string2.begin();
+  StringPieceType::const_iterator string1end = string1.end();
+  StringPieceType::const_iterator string2end = string2.end();
   for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
     wchar_t c1 =
         (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
@@ -709,7 +708,7 @@
 }
 
 #elif defined(OS_MACOSX)
-// Mac OS X specific implementation of file string comparisons
+// Mac OS X specific implementation of file string comparisons.
 
 // cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
 //
@@ -1153,25 +1152,23 @@
   return codepoint;
 }
 
-}  // anonymous namespace
+}  // namespace
 
 // Special UTF-8 version of FastUnicodeCompare. Cf:
 // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
 // The input strings must be in the special HFS decomposed form.
-int FilePath::HFSFastUnicodeCompare(const StringType& string1,
-                                    const StringType& string2) {
+int FilePath::HFSFastUnicodeCompare(StringPieceType string1,
+                                    StringPieceType string2) {
   int length1 = string1.length();
   int length2 = string2.length();
   int index1 = 0;
   int index2 = 0;
 
   for (;;) {
-    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(),
-                                                      length1,
-                                                      &index1);
-    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(),
-                                                      length2,
-                                                      &index2);
+    int codepoint1 =
+        HFSReadNextNonIgnorableCodepoint(string1.data(), length1, &index1);
+    int codepoint2 =
+        HFSReadNextNonIgnorableCodepoint(string2.data(), length2, &index2);
     if (codepoint1 != codepoint2)
       return (codepoint1 < codepoint2) ? -1 : 1;
     if (codepoint1 == 0) {
@@ -1182,15 +1179,10 @@
   }
 }
 
-StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
-  ScopedCFTypeRef<CFStringRef> cfstring(
-      CFStringCreateWithBytesNoCopy(
-          NULL,
-          reinterpret_cast<const UInt8*>(string.c_str()),
-          string.length(),
-          kCFStringEncodingUTF8,
-          false,
-          kCFAllocatorNull));
+StringType FilePath::GetHFSDecomposedForm(StringPieceType string) {
+  ScopedCFTypeRef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
+      NULL, reinterpret_cast<const UInt8*>(string.data()), string.length(),
+      kCFStringEncodingUTF8, false, kCFAllocatorNull));
   // Query the maximum length needed to store the result. In most cases this
   // will overestimate the required space. The return value also already
   // includes the space needed for a terminating 0.
@@ -1215,8 +1207,8 @@
   return result;
 }
 
-int FilePath::CompareIgnoreCase(const StringType& string1,
-                                const StringType& string2) {
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType string2) {
   // Quick checks for empty strings - these speed things up a bit and make the
   // following code cleaner.
   if (string1.empty())
@@ -1230,22 +1222,12 @@
   // GetHFSDecomposedForm() returns an empty string in an error case.
   if (hfs1.empty() || hfs2.empty()) {
     NOTREACHED();
-    ScopedCFTypeRef<CFStringRef> cfstring1(
-        CFStringCreateWithBytesNoCopy(
-            NULL,
-            reinterpret_cast<const UInt8*>(string1.c_str()),
-            string1.length(),
-            kCFStringEncodingUTF8,
-            false,
-            kCFAllocatorNull));
-    ScopedCFTypeRef<CFStringRef> cfstring2(
-        CFStringCreateWithBytesNoCopy(
-            NULL,
-            reinterpret_cast<const UInt8*>(string2.c_str()),
-            string2.length(),
-            kCFStringEncodingUTF8,
-            false,
-            kCFAllocatorNull));
+    ScopedCFTypeRef<CFStringRef> cfstring1(CFStringCreateWithBytesNoCopy(
+        NULL, reinterpret_cast<const UInt8*>(string1.data()), string1.length(),
+        kCFStringEncodingUTF8, false, kCFAllocatorNull));
+    ScopedCFTypeRef<CFStringRef> cfstring2(CFStringCreateWithBytesNoCopy(
+        NULL, reinterpret_cast<const UInt8*>(string2.data()), string2.length(),
+        kCFStringEncodingUTF8, false, kCFAllocatorNull));
     return CFStringCompare(cfstring1,
                            cfstring2,
                            kCFCompareCaseInsensitive);
@@ -1256,11 +1238,12 @@
 
 #else  // << WIN. MACOSX | other (POSIX) >>
 
-// Generic (POSIX) implementation of file string comparison.
-// TODO(rolandsteiner) check if this is sufficient/correct.
-int FilePath::CompareIgnoreCase(const StringType& string1,
-                                const StringType& string2) {
-  int comparison = strcasecmp(string1.c_str(), string2.c_str());
+// Generic Posix system comparisons.
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType string2) {
+  // Specifically need null termianted strings for this API call.
+  int comparison =
+      strcasecmp(string1.as_string().c_str(), string2.as_string().c_str());
   if (comparison < 0)
     return -1;
   if (comparison > 0)
diff --git a/base/files/file_path.h b/base/files/file_path.h
index 0c84af6..f10503e 100644
--- a/base/files/file_path.h
+++ b/base/files/file_path.h
@@ -112,7 +112,7 @@
 #include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
 #include "base/strings/string16.h"
-#include "base/strings/string_piece.h"  // For implicit conversions.
+#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 
 // Windows-style drive letter support and pathname separator characters can be
@@ -144,6 +144,7 @@
   typedef std::wstring StringType;
 #endif  // OS_WIN
 
+  typedef BasicStringPiece<StringType> StringPieceType;
   typedef StringType::value_type CharType;
 
   // Null-terminated array of separators used to separate components in
@@ -166,7 +167,7 @@
 
   FilePath();
   FilePath(const FilePath& that);
-  explicit FilePath(const StringType& path);
+  explicit FilePath(StringPieceType path);
   ~FilePath();
   FilePath& operator=(const FilePath& that);
 
@@ -267,26 +268,24 @@
   // path == "jojo.jpg"         suffix == " (1)", returns "jojo (1).jpg"
   // path == "C:\pics\jojo"     suffix == " (1)", returns "C:\pics\jojo (1)"
   // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
-  FilePath InsertBeforeExtension(
-      const StringType& suffix) const WARN_UNUSED_RESULT;
-  FilePath InsertBeforeExtensionASCII(
-      const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
+  FilePath InsertBeforeExtension(StringPieceType suffix) const
+      WARN_UNUSED_RESULT;
+  FilePath InsertBeforeExtensionASCII(StringPiece suffix) const
+      WARN_UNUSED_RESULT;
 
   // Adds |extension| to |file_name|. Returns the current FilePath if
   // |extension| is empty. Returns "" if BaseName() == "." or "..".
-  FilePath AddExtension(
-      const StringType& extension) const WARN_UNUSED_RESULT;
+  FilePath AddExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
 
   // Replaces the extension of |file_name| with |extension|.  If |file_name|
   // does not have an extension, then |extension| is added.  If |extension| is
   // empty, then the extension is removed from |file_name|.
   // Returns "" if BaseName() == "." or "..".
-  FilePath ReplaceExtension(
-      const StringType& extension) const WARN_UNUSED_RESULT;
+  FilePath ReplaceExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
 
   // Returns true if the file path matches the specified extension. The test is
   // case insensitive. Don't forget the leading period if appropriate.
-  bool MatchesExtension(const StringType& extension) const;
+  bool MatchesExtension(StringPieceType extension) const;
 
   // Returns a FilePath by appending a separator and the supplied path
   // component to this object's path.  Append takes care to avoid adding
@@ -294,7 +293,7 @@
   // If this object's path is kCurrentDirectory, a new FilePath corresponding
   // only to |component| is returned.  |component| must be a relative path;
   // it is an error to pass an absolute path.
-  FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
+  FilePath Append(StringPieceType component) const WARN_UNUSED_RESULT;
   FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
 
   // Although Windows StringType is std::wstring, since the encoding it uses for
@@ -303,8 +302,7 @@
   // On Linux, although it can use any 8-bit encoding for paths, we assume that
   // ASCII is a valid subset, regardless of the encoding, since many operating
   // system paths will always be ASCII.
-  FilePath AppendASCII(const base::StringPiece& component)
-      const WARN_UNUSED_RESULT;
+  FilePath AppendASCII(StringPiece component) const WARN_UNUSED_RESULT;
 
   // Returns true if this FilePath contains an absolute path.  On Windows, an
   // absolute path begins with either a drive letter specification followed by
@@ -388,14 +386,14 @@
   // on parts of a file path, e.g., just the extension.
   // CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
   // greater-than respectively.
-  static int CompareIgnoreCase(const StringType& string1,
-                               const StringType& string2);
-  static bool CompareEqualIgnoreCase(const StringType& string1,
-                                     const StringType& string2) {
+  static int CompareIgnoreCase(StringPieceType string1,
+                               StringPieceType string2);
+  static bool CompareEqualIgnoreCase(StringPieceType string1,
+                                     StringPieceType string2) {
     return CompareIgnoreCase(string1, string2) == 0;
   }
-  static bool CompareLessIgnoreCase(const StringType& string1,
-                                    const StringType& string2) {
+  static bool CompareLessIgnoreCase(StringPieceType string1,
+                                    StringPieceType string2) {
     return CompareIgnoreCase(string1, string2) < 0;
   }
 
@@ -405,14 +403,14 @@
   // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
   // for further comments.
   // Returns the epmty string if the conversion failed.
-  static StringType GetHFSDecomposedForm(const FilePath::StringType& string);
+  static StringType GetHFSDecomposedForm(StringPieceType string);
 
   // Special UTF-8 version of FastUnicodeCompare. Cf:
   // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
   // IMPORTANT: The input strings must be in the special HFS decomposed form!
   // (cf. above GetHFSDecomposedForm method)
-  static int HFSFastUnicodeCompare(const StringType& string1,
-                                   const StringType& string2);
+  static int HFSFastUnicodeCompare(StringPieceType string1,
+                                   StringPieceType string2);
 #endif
 
 #if defined(OS_ANDROID)
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index bb49d2d..7fb617c 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -466,7 +466,7 @@
 // NaCl doesn't implement system calls to open files directly.
 #if !defined(OS_NACL)
 // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
-void File::DoInitialize(uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32 flags) {
   ThreadRestrictions::AssertIOAllowed();
   DCHECK(!IsValid());
 
@@ -521,7 +521,7 @@
   mode |= S_IRGRP | S_IROTH;
 #endif
 
-  int descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+  int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
 
   if (flags & FLAG_OPEN_ALWAYS) {
     if (descriptor < 0) {
@@ -529,7 +529,7 @@
       if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
         open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
 
-      descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+      descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
       if (descriptor >= 0)
         created_ = true;
     }
@@ -544,7 +544,7 @@
     created_ = true;
 
   if (flags & FLAG_DELETE_ON_CLOSE)
-    unlink(path_.value().c_str());
+    unlink(path.value().c_str());
 
   async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
   error_details_ = FILE_OK;
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc
index c25772d..92a5780 100644
--- a/base/files/file_tracing.cc
+++ b/base/files/file_tracing.cc
@@ -13,6 +13,11 @@
 }
 
 // static
+bool FileTracing::IsCategoryEnabled() {
+  return g_provider && g_provider->FileTracingCategoryIsEnabled();
+}
+
+// static
 void FileTracing::SetProvider(FileTracing::Provider* provider) {
   g_provider = provider;
 }
@@ -34,19 +39,11 @@
     g_provider->FileTracingEventEnd(name_, id_);
 }
 
-bool FileTracing::ScopedTrace::ShouldInitialize() const {
-  return g_provider && g_provider->FileTracingCategoryIsEnabled();
-}
-
 void FileTracing::ScopedTrace::Initialize(
     const char* name, File* file, int64 size) {
-  if (!g_provider)
-    return;
-
   id_ = &file->trace_enabler_;
   name_ = name;
-
-  g_provider->FileTracingEventBegin(name_, id_, file->path_, size);
+  g_provider->FileTracingEventBegin(name_, id_, file->tracing_path_, size);
 }
 
 }  // namespace base
diff --git a/base/files/file_tracing.h b/base/files/file_tracing.h
index 149bd78..373fe0e 100644
--- a/base/files/file_tracing.h
+++ b/base/files/file_tracing.h
@@ -12,9 +12,9 @@
 #define FILE_TRACING_PREFIX "File"
 
 #define SCOPED_FILE_TRACE_WITH_SIZE(name, size) \
-    FileTracing::ScopedTrace scoped_file_trace; \
-    if (scoped_file_trace.ShouldInitialize()) \
-      scoped_file_trace.Initialize(FILE_TRACING_PREFIX "::" name, this, size)
+  FileTracing::ScopedTrace scoped_file_trace;   \
+  if (FileTracing::IsCategoryEnabled())         \
+  scoped_file_trace.Initialize(FILE_TRACING_PREFIX "::" name, this, size)
 
 #define SCOPED_FILE_TRACE(name) SCOPED_FILE_TRACE_WITH_SIZE(name, 0)
 
@@ -25,8 +25,13 @@
 
 class BASE_EXPORT FileTracing {
  public:
+  // Whether the file tracing category is enabled.
+  static bool IsCategoryEnabled();
+
   class Provider {
    public:
+    virtual ~Provider() = default;
+
     // Whether the file tracing category is currently enabled.
     virtual bool FileTracingCategoryIsEnabled() const = 0;
 
@@ -61,9 +66,6 @@
     ScopedTrace();
     ~ScopedTrace();
 
-    // Whether this trace should be initialized or not.
-    bool ShouldInitialize() const;
-
     // Called only if the tracing category is enabled. |name| is the name of the
     // event to trace (e.g. "Read", "Write") and must have an application
     // lifetime (e.g. static or literal). |file| is the file being traced; must
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
index 9792852..ccecb70 100644
--- a/base/files/file_win.cc
+++ b/base/files/file_win.cc
@@ -308,7 +308,7 @@
   }
 }
 
-void File::DoInitialize(uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32 flags) {
   ThreadRestrictions::AssertIOAllowed();
   DCHECK(!IsValid());
 
@@ -376,8 +376,8 @@
   if (flags & FLAG_BACKUP_SEMANTICS)
     create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
 
-  file_.Set(CreateFile(path_.value().c_str(), access, sharing, NULL,
-                       disposition, create_flags, NULL));
+  file_.Set(CreateFile(path.value().c_str(), access, sharing, NULL, disposition,
+                       create_flags, NULL));
 
   if (file_.IsValid()) {
     error_details_ = FILE_OK;
diff --git a/base/files/memory_mapped_file.cc b/base/files/memory_mapped_file.cc
index bad1792..227a41f 100644
--- a/base/files/memory_mapped_file.cc
+++ b/base/files/memory_mapped_file.cc
@@ -10,18 +10,7 @@
 
 namespace base {
 
-const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile(
-    base::LINKER_INITIALIZED);
-
-MemoryMappedFile::Region::Region(base::LinkerInitialized) : offset(0), size(0) {
-}
-
-MemoryMappedFile::Region::Region() : offset(-1), size(-1) {
-}
-
-MemoryMappedFile::Region::Region(int64 offset, int64 size)
-    : offset(offset), size(size) {
-}
+const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile = {0, 0};
 
 bool MemoryMappedFile::Region::operator==(
     const MemoryMappedFile::Region& other) const {
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h
index 96d1d91..9ff29b9 100644
--- a/base/files/memory_mapped_file.h
+++ b/base/files/memory_mapped_file.h
@@ -28,9 +28,6 @@
   struct BASE_EXPORT Region {
     static const Region kWholeFile;
 
-    Region();
-    Region(int64 offset, int64 size);
-
     bool operator==(const Region& other) const;
     bool operator!=(const Region& other) const;
 
@@ -39,10 +36,6 @@
 
     // Length of the region in bytes.
     int64 size;
-
-   private:
-    // Used by kWholeFile.
-    Region(base::LinkerInitialized);
   };
 
   // Opens an existing file and maps it into memory. Access is restricted to
diff --git a/base/files/memory_mapped_file_unittest.cc b/base/files/memory_mapped_file_unittest.cc
index d0833b5..05b941c 100644
--- a/base/files/memory_mapped_file_unittest.cc
+++ b/base/files/memory_mapped_file_unittest.cc
@@ -107,7 +107,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(0, kPartialSize));
+  MemoryMappedFile::Region region = {0, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
@@ -122,7 +123,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  MemoryMappedFile::Region region = {kOffset, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
@@ -138,7 +140,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  MemoryMappedFile::Region region = {kOffset, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
@@ -154,7 +157,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  MemoryMappedFile::Region region = {kOffset, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
diff --git a/base/files/memory_mapped_file_win.cc b/base/files/memory_mapped_file_win.cc
index 4e7e934..8585906 100644
--- a/base/files/memory_mapped_file_win.cc
+++ b/base/files/memory_mapped_file_win.cc
@@ -32,7 +32,7 @@
   if (!file_mapping_.IsValid())
     return false;
 
-  LARGE_INTEGER map_start = {0};
+  LARGE_INTEGER map_start = {};
   SIZE_T map_size = 0;
   int32 data_offset = 0;
 
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
index 8c81d85..80da731 100644
--- a/base/i18n/bidi_line_iterator.cc
+++ b/base/i18n/bidi_line_iterator.cc
@@ -9,6 +9,25 @@
 namespace base {
 namespace i18n {
 
+namespace {
+UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) {
+  switch (direction) {
+    case UNKNOWN_DIRECTION:
+      return UBIDI_DEFAULT_LTR;
+      break;
+    case RIGHT_TO_LEFT:
+      return 1;  // Highest RTL level.
+      break;
+    case LEFT_TO_RIGHT:
+      return 0;  // Highest LTR level.
+      break;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+}  // namespace
+
 BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
 }
 
@@ -19,15 +38,14 @@
   }
 }
 
-bool BiDiLineIterator::Open(const string16& text, bool right_to_left) {
+bool BiDiLineIterator::Open(const string16& text, TextDirection direction) {
   DCHECK(!bidi_);
   UErrorCode error = U_ZERO_ERROR;
   bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
   if (U_FAILURE(error))
     return false;
   ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
-                right_to_left ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
-                NULL, &error);
+                GetParagraphLevelForDirection(direction), NULL, &error);
   return (U_SUCCESS(error) == TRUE);
 }
 
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
index 07d9aa2..0bf1ec6 100644
--- a/base/i18n/bidi_line_iterator.h
+++ b/base/i18n/bidi_line_iterator.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/i18n/base_i18n_export.h"
+#include "base/i18n/rtl.h"
 #include "base/strings/string16.h"
 #include "third_party/icu/source/common/unicode/ubidi.h"
 
@@ -23,7 +24,7 @@
 
   // Initializes the bidirectional iterator with the specified text.  Returns
   // whether initialization succeeded.
-  bool Open(const string16& text, bool right_to_left);
+  bool Open(const string16& text, TextDirection direction);
 
   // Returns the number of visual runs in the text, or zero on error.
   int CountRuns();
diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc
index 5debc2e..d0eceb9 100644
--- a/base/i18n/case_conversion.cc
+++ b/base/i18n/case_conversion.cc
@@ -4,22 +4,91 @@
 
 #include "base/i18n/case_conversion.h"
 
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
 #include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
 
 namespace base {
 namespace i18n {
 
-string16 ToLower(const StringPiece16& string) {
-  icu::UnicodeString unicode_string(string.data(), string.size());
-  unicode_string.toLower();
-  return string16(unicode_string.getBuffer(), unicode_string.length());
+namespace {
+
+// Provides a uniform interface for upper/lower/folding which take take
+// slightly varying parameters.
+typedef int32_t (*CaseMapperFunction)(UChar* dest,
+                                      int32_t dest_capacity,
+                                      const UChar* src,
+                                      int32_t src_length,
+                                      UErrorCode* error);
+
+int32_t ToUpperMapper(UChar* dest,
+                      int32_t dest_capacity,
+                      const UChar* src,
+                      int32_t src_length,
+                      UErrorCode* error) {
+  // Use default locale.
+  return u_strToUpper(dest, dest_capacity, src, src_length, NULL, error);
 }
 
-string16 ToUpper(const StringPiece16& string) {
-  icu::UnicodeString unicode_string(string.data(), string.size());
-  unicode_string.toUpper();
-  return string16(unicode_string.getBuffer(), unicode_string.length());
+int32_t ToLowerMapper(UChar* dest,
+                      int32_t dest_capacity,
+                      const UChar* src,
+                      int32_t src_length,
+                      UErrorCode* error) {
+  // Use default locale.
+  return u_strToLower(dest, dest_capacity, src, src_length, NULL, error);
+}
+
+int32_t FoldCaseMapper(UChar* dest,
+                       int32_t dest_capacity,
+                       const UChar* src,
+                       int32_t src_length,
+                       UErrorCode* error) {
+  return u_strFoldCase(dest, dest_capacity, src, src_length,
+                       U_FOLD_CASE_DEFAULT, error);
+}
+
+// Provides similar functionality as UnicodeString::caseMap but on string16.
+string16 CaseMap(StringPiece16 string, CaseMapperFunction case_mapper) {
+  string16 dest;
+  if (string.empty())
+    return dest;
+
+  // Provide an initial guess that the string length won't change. The typical
+  // strings we use will very rarely change length in this process, so don't
+  // optimize for that case.
+  dest.resize(string.size());
+
+  UErrorCode error;
+  do {
+    error = U_ZERO_ERROR;
+
+    // ICU won't terminate the string if there's not enough room for the null
+    // terminator, but will otherwise. So we don't need to save room for that.
+    // Don't use WriteInto, which assumes null terminators.
+    int32_t new_length = case_mapper(
+        &dest[0], saturated_cast<int32_t>(dest.size()), string.data(),
+        saturated_cast<int32_t>(string.size()), &error);
+    dest.resize(new_length);
+  } while (error == U_BUFFER_OVERFLOW_ERROR);
+  return dest;
+}
+
+}  // namespace
+
+string16 ToLower(StringPiece16 string) {
+  return CaseMap(string, &ToLowerMapper);
+}
+
+string16 ToUpper(StringPiece16 string) {
+  return CaseMap(string, &ToUpperMapper);
+}
+
+string16 FoldCase(StringPiece16 string) {
+  return CaseMap(string, &FoldCaseMapper);
 }
 
 }  // namespace i18n
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h
index 5d538cc..0631a80 100644
--- a/base/i18n/case_conversion.h
+++ b/base/i18n/case_conversion.h
@@ -12,11 +12,35 @@
 namespace base {
 namespace i18n {
 
-// Returns the lower case equivalent of string. Uses ICU's default locale.
-BASE_I18N_EXPORT string16 ToLower(const StringPiece16& string);
+// UNICODE CASE-HANDLING ADVICE
+//
+// In English it's always safe to convert to upper-case or lower-case text
+// and get a good answer. But some languages have rules specific to those
+// locales. One example is the Turkish I:
+//   http://www.i18nguy.com/unicode/turkish-i18n.html
+//
+// ToLower/ToUpper use the current ICU locale which will take into account
+// the user language preference. Use this when dealing with user typing.
+//
+// FoldCase canonicalizes to a standardized form independent of the current
+// locale. Use this when comparing general Unicode strings that don't
+// necessarily belong in the user's current locale (like commands, protocol
+// names, other strings from the web) for case-insensitive equality.
+//
+// Note that case conversions will change the length of the string in some
+// not-uncommon cases. Never assume that the output is the same length as
+// the input.
 
-// Returns the upper case equivalent of string. Uses ICU's default locale.
-BASE_I18N_EXPORT string16 ToUpper(const StringPiece16& string);
+// Returns the lower case equivalent of string. Uses ICU's current locale.
+BASE_I18N_EXPORT string16 ToLower(StringPiece16 string);
+
+// Returns the upper case equivalent of string. Uses ICU's current locale.
+BASE_I18N_EXPORT string16 ToUpper(StringPiece16 string);
+
+// Convert the given string to a canonical case, independent of the current
+// locale. For ASCII the canonical form is lower case.
+// See http://unicode.org/faq/casemap_charprop.html#2
+BASE_I18N_EXPORT string16 FoldCase(StringPiece16 string);
 
 }  // namespace i18n
 }  // namespace base
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc
index 75e5ad2..dc5bc1f 100644
--- a/base/i18n/case_conversion_unittest.cc
+++ b/base/i18n/case_conversion_unittest.cc
@@ -9,39 +9,47 @@
 #include "third_party/icu/source/i18n/unicode/usearch.h"
 
 namespace base {
+namespace i18n {
+
 namespace {
 
+const wchar_t kNonASCIIMixed[] =
+    L"\xC4\xD6\xE4\xF6\x20\xCF\xEF\x20\xF7\x25"
+    L"\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07\x1F0F"
+    L"\x20\x1E00\x1E01";
+const wchar_t kNonASCIILower[] =
+    L"\xE4\xF6\xE4\xF6\x20\xEF\xEF"
+    L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07"
+    L"\x1F07\x20\x1E01\x1E01";
+const wchar_t kNonASCIIUpper[] =
+    L"\xC4\xD6\xC4\xD6\x20\xCF\xCF"
+    L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F0F"
+    L"\x1F0F\x20\x1E00\x1E00";
+
+}  // namespace
+
 // Test upper and lower case string conversion.
 TEST(CaseConversionTest, UpperLower) {
   const string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
   const string16 expected_lower(ASCIIToUTF16("text with upper & lower case."));
   const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE."));
 
-  string16 result = base::i18n::ToLower(mixed);
+  string16 result = ToLower(mixed);
   EXPECT_EQ(expected_lower, result);
 
-  result = base::i18n::ToUpper(mixed);
+  result = ToUpper(mixed);
   EXPECT_EQ(expected_upper, result);
 }
 
 TEST(CaseConversionTest, NonASCII) {
-  const string16 mixed(WideToUTF16(
-      L"\xC4\xD6\xE4\xF6\x20\xCF\xEF\x20\xF7\x25"
-      L"\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07\x1F0F"
-      L"\x20\x1E00\x1E01"));
-  const string16 expected_lower(WideToUTF16(
-      L"\xE4\xF6\xE4\xF6\x20\xEF\xEF"
-      L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07"
-      L"\x1F07\x20\x1E01\x1E01"));
-  const string16 expected_upper(WideToUTF16(
-      L"\xC4\xD6\xC4\xD6\x20\xCF\xCF"
-      L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F0F"
-      L"\x1F0F\x20\x1E00\x1E00"));
+  const string16 mixed(WideToUTF16(kNonASCIIMixed));
+  const string16 expected_lower(WideToUTF16(kNonASCIILower));
+  const string16 expected_upper(WideToUTF16(kNonASCIIUpper));
 
-  string16 result = base::i18n::ToLower(mixed);
+  string16 result = ToLower(mixed);
   EXPECT_EQ(expected_lower, result);
 
-  result = base::i18n::ToUpper(mixed);
+  result = ToUpper(mixed);
   EXPECT_EQ(expected_upper, result);
 }
 
@@ -53,10 +61,10 @@
   std::string default_locale(uloc_getDefault());
   i18n::SetICUDefaultLocale("en_US");
 
-  string16 result = base::i18n::ToLower(mixed);
+  string16 result = ToLower(mixed);
   EXPECT_EQ(expected_lower, result);
 
-  result = base::i18n::ToUpper(mixed);
+  result = ToUpper(mixed);
   EXPECT_EQ(expected_upper, result);
 
   i18n::SetICUDefaultLocale("tr");
@@ -64,16 +72,48 @@
   const string16 expected_lower_turkish(WideToUTF16(L"\x131\x131"));
   const string16 expected_upper_turkish(WideToUTF16(L"\x49\x49"));
 
-  result = base::i18n::ToLower(mixed);
+  result = ToLower(mixed);
   EXPECT_EQ(expected_lower_turkish, result);
 
-  result = base::i18n::ToUpper(mixed);
+  result = ToUpper(mixed);
   EXPECT_EQ(expected_upper_turkish, result);
 
-  base::i18n::SetICUDefaultLocale(default_locale.data());
+  SetICUDefaultLocale(default_locale.data());
 }
 
-}  // namespace
+TEST(CaseConversionTest, FoldCase) {
+  // Simple ASCII, should lower-case.
+  EXPECT_EQ(ASCIIToUTF16("hello, world"),
+            FoldCase(ASCIIToUTF16("Hello, World")));
+
+  // Non-ASCII cases from above. They should all fold to the same result.
+  EXPECT_EQ(FoldCase(WideToUTF16(kNonASCIIMixed)),
+            FoldCase(WideToUTF16(kNonASCIILower)));
+  EXPECT_EQ(FoldCase(WideToUTF16(kNonASCIIMixed)),
+            FoldCase(WideToUTF16(kNonASCIIUpper)));
+
+  // Turkish cases from above. This is the lower-case expected result from the
+  // US locale. It should be the same even when the current locale is Turkish.
+  const string16 turkish(WideToUTF16(L"\x49\x131"));
+  const string16 turkish_expected(WideToUTF16(L"\x69\x131"));
+
+  std::string default_locale(uloc_getDefault());
+  i18n::SetICUDefaultLocale("en_US");
+  EXPECT_EQ(turkish_expected, FoldCase(turkish));
+
+  i18n::SetICUDefaultLocale("tr");
+  EXPECT_EQ(turkish_expected, FoldCase(turkish));
+
+  // Test a case that gets bigger when processed.
+  // U+130 = LATIN CAPITAL LETTER I WITH DOT ABOVE gets folded to a lower case
+  // "i" followed by U+307 COMBINING DOT ABOVE.
+  EXPECT_EQ(WideToUTF16(L"i\u0307j"), FoldCase(WideToUTF16(L"\u0130j")));
+
+  // U+00DF (SHARP S) and U+1E9E (CAPIRAL SHARP S) are both folded to "ss".
+  EXPECT_EQ(ASCIIToUTF16("ssss"), FoldCase(WideToUTF16(L"\u00DF\u1E9E")));
+}
+
+}  // namespace i18n
 }  // namespace base
 
 
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index a9f0b12..1dd54cd 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -23,6 +23,10 @@
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "base/android/apk_assets.h"
+#endif
+
 #if defined(OS_MACOSX)
 #include "base/mac/foundation_util.h"
 #endif
@@ -34,11 +38,6 @@
 namespace base {
 namespace i18n {
 
-// Use an unversioned file name to simplify a icu version update down the road.
-// No need to change the filename in multiple places (gyp files, windows
-// build pkg configurations, etc). 'l' stands for Little Endian.
-// This variable is exported through the header file.
-const char kIcuDataFileName[] = "icudtl.dat";
 #if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
 #define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
 #if defined(OS_WIN)
@@ -47,44 +46,140 @@
 #endif
 
 namespace {
-
+#if !defined(OS_NACL)
 #if !defined(NDEBUG)
 // Assert that we are not called more than once.  Even though calling this
 // function isn't harmful (ICU can handle it), being called twice probably
 // indicates a programming error.
-#if !defined(OS_NACL)
-bool g_called_once = false;
-#endif
 bool g_check_called_once = true;
+bool g_called_once = false;
+#endif  // !defined(NDEBUG)
+
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+// Use an unversioned file name to simplify a icu version update down the road.
+// No need to change the filename in multiple places (gyp files, windows
+// build pkg configurations, etc). 'l' stands for Little Endian.
+// This variable is exported through the header file.
+const char kIcuDataFileName[] = "icudtl.dat";
+#if defined(OS_ANDROID)
+const char kAndroidAssetsIcuDataFileName[] = "assets/icudtl.dat";
 #endif
+
+// File handle intentionally never closed. Not using File here because its
+// Windows implementation guards against two instances owning the same
+// PlatformFile (which we allow since we know it is never freed).
+const PlatformFile kInvalidPlatformFile =
+#if defined(OS_WIN)
+    INVALID_HANDLE_VALUE;
+#else
+    -1;
+#endif
+PlatformFile g_icudtl_pf = kInvalidPlatformFile;
+MemoryMappedFile* g_icudtl_mapped_file = nullptr;
+MemoryMappedFile::Region g_icudtl_region;
+
+void LazyInitIcuDataFile() {
+  if (g_icudtl_pf != kInvalidPlatformFile) {
+    return;
+  }
+#if defined(OS_ANDROID)
+  int fd = base::android::OpenApkAsset(kAndroidAssetsIcuDataFileName,
+                                       &g_icudtl_region);
+  g_icudtl_pf = fd;
+  if (fd != -1) {
+    return;
+  }
+// For unit tests, data file is located on disk, so try there as a fallback.
+#endif  // defined(OS_ANDROID)
+#if !defined(OS_MACOSX)
+  FilePath data_path;
+#if defined(OS_WIN)
+  // The data file will be in the same directory as the current module.
+  bool path_ok = PathService::Get(DIR_MODULE, &data_path);
+  wchar_t tmp_buffer[_MAX_PATH] = {0};
+  wcscpy_s(tmp_buffer, data_path.value().c_str());
+  debug::Alias(tmp_buffer);
+  CHECK(path_ok);  // TODO(scottmg): http://crbug.com/445616
+#elif defined(OS_ANDROID)
+  bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
+#else
+  // For now, expect the data file to be alongside the executable.
+  // This is sufficient while we work on unit tests, but will eventually
+  // likely live in a data directory.
+  bool path_ok = PathService::Get(DIR_EXE, &data_path);
+#endif
+  DCHECK(path_ok);
+  data_path = data_path.AppendASCII(kIcuDataFileName);
+
+#if defined(OS_WIN)
+  // TODO(scottmg): http://crbug.com/445616
+  wchar_t tmp_buffer2[_MAX_PATH] = {0};
+  wcscpy_s(tmp_buffer2, data_path.value().c_str());
+  debug::Alias(tmp_buffer2);
+#endif
+
+#else
+  // Assume it is in the framework bundle's Resources directory.
+  ScopedCFTypeRef<CFStringRef> data_file_name(
+      SysUTF8ToCFStringRef(kIcuDataFileName));
+  FilePath data_path = mac::PathForFrameworkBundleResource(data_file_name);
+  if (data_path.empty()) {
+    LOG(ERROR) << kIcuDataFileName << " not found in bundle";
+    return;
+  }
+#endif  // !defined(OS_MACOSX)
+  File file(data_path, File::FLAG_OPEN | File::FLAG_READ);
+  if (file.IsValid()) {
+    g_icudtl_pf = file.TakePlatformFile();
+    g_icudtl_region = MemoryMappedFile::Region::kWholeFile;
+  }
 }
 
+bool InitializeICUWithFileDescriptorInternal(
+    PlatformFile data_fd,
+    const MemoryMappedFile::Region& data_region) {
+  // This can be called multiple times in tests.
+  if (g_icudtl_mapped_file) {
+    return true;
+  }
+  if (data_fd == kInvalidPlatformFile) {
+    return false;
+  }
+
+  scoped_ptr<MemoryMappedFile> icudtl_mapped_file(new MemoryMappedFile());
+  if (!icudtl_mapped_file->Initialize(File(data_fd), data_region)) {
+    LOG(ERROR) << "Couldn't mmap icu data file";
+    return false;
+  }
+  g_icudtl_mapped_file = icudtl_mapped_file.release();
+
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(g_icudtl_mapped_file->data()), &err);
+  return err == U_ZERO_ERROR;
+}
+#endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#endif  // !defined(OS_NACL)
+
+}  // namespace
+
 #if !defined(OS_NACL)
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
 bool InitializeICUWithFileDescriptor(
     PlatformFile data_fd,
-    MemoryMappedFile::Region data_region) {
+    const MemoryMappedFile::Region& data_region) {
 #if !defined(NDEBUG)
   DCHECK(!g_check_called_once || !g_called_once);
   g_called_once = true;
 #endif
-
-#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
-  // The ICU data is statically linked.
-  return true;
-#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
-  CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
-  if (!mapped_file.IsValid()) {
-    if (!mapped_file.Initialize(File(data_fd), data_region)) {
-      LOG(ERROR) << "Couldn't mmap icu data file";
-      return false;
-    }
-  }
-  UErrorCode err = U_ZERO_ERROR;
-  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
-  return err == U_ZERO_ERROR;
-#endif // ICU_UTIL_DATA_FILE
+  return InitializeICUWithFileDescriptorInternal(data_fd, data_region);
 }
 
+PlatformFile GetIcuDataFileHandle(MemoryMappedFile::Region* out_region) {
+  CHECK_NE(g_icudtl_pf, kInvalidPlatformFile);
+  *out_region = g_icudtl_region;
+  return g_icudtl_pf;
+}
+#endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
 
 bool InitializeICU() {
 #if !defined(NDEBUG)
@@ -123,60 +218,9 @@
   // it is needed.  This can fail if the process is sandboxed at that time.
   // Instead, we map the file in and hand off the data so the sandbox won't
   // cause any problems.
-
-  // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
-  // be released.
-  CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
-  if (!mapped_file.IsValid()) {
-#if !defined(OS_MACOSX)
-    FilePath data_path;
-#if defined(OS_WIN)
-    // The data file will be in the same directory as the current module.
-    bool path_ok = PathService::Get(DIR_MODULE, &data_path);
-    wchar_t tmp_buffer[_MAX_PATH] = {0};
-    wcscpy_s(tmp_buffer, data_path.value().c_str());
-    debug::Alias(tmp_buffer);
-    CHECK(path_ok);  // TODO(scottmg): http://crbug.com/445616
-#elif defined(OS_ANDROID)
-    bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
-#else
-    // For now, expect the data file to be alongside the executable.
-    // This is sufficient while we work on unit tests, but will eventually
-    // likely live in a data directory.
-    bool path_ok = PathService::Get(DIR_EXE, &data_path);
-#endif
-    DCHECK(path_ok);
-    data_path = data_path.AppendASCII(kIcuDataFileName);
-
-#if defined(OS_WIN)
-    // TODO(scottmg): http://crbug.com/445616
-    wchar_t tmp_buffer2[_MAX_PATH] = {0};
-    wcscpy_s(tmp_buffer2, data_path.value().c_str());
-    debug::Alias(tmp_buffer2);
-#endif
-
-#else
-    // Assume it is in the framework bundle's Resources directory.
-    ScopedCFTypeRef<CFStringRef> data_file_name(
-        SysUTF8ToCFStringRef(kIcuDataFileName));
-    FilePath data_path =
-      mac::PathForFrameworkBundleResource(data_file_name);
-    if (data_path.empty()) {
-      LOG(ERROR) << kIcuDataFileName << " not found in bundle";
-      return false;
-    }
-#endif  // OS check
-    if (!mapped_file.Initialize(data_path)) {
-#if defined(OS_WIN)
-      CHECK(false);  // TODO(scottmg): http://crbug.com/445616
-#endif
-      LOG(ERROR) << "Couldn't mmap " << data_path.AsUTF8Unsafe();
-      return false;
-    }
-  }
-  UErrorCode err = U_ZERO_ERROR;
-  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
-  result = (err == U_ZERO_ERROR);
+  LazyInitIcuDataFile();
+  result =
+      InitializeICUWithFileDescriptorInternal(g_icudtl_pf, g_icudtl_region);
 #if defined(OS_WIN)
   CHECK(result);  // TODO(scottmg): http://crbug.com/445616
 #endif
@@ -193,10 +237,10 @@
 #endif
   return result;
 }
-#endif
+#endif  // !defined(OS_NACL)
 
 void AllowMultipleInitializeCallsForTesting() {
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) && !defined(OS_NACL)
   g_check_called_once = false;
 #endif
 }
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
index 65de0ad..1de4172 100644
--- a/base/i18n/icu_util.h
+++ b/base/i18n/icu_util.h
@@ -12,19 +12,24 @@
 namespace base {
 namespace i18n {
 
-BASE_I18N_EXPORT extern const char kIcuDataFileName[];
-
 #if !defined(OS_NACL)
 // Call this function to load ICU's data tables for the current process.  This
 // function should be called before ICU is used.
 BASE_I18N_EXPORT bool InitializeICU();
 
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+// Returns the PlatformFile and Region that was initialized by InitializeICU().
+// Use with InitializeICUWithFileDescriptor().
+BASE_I18N_EXPORT PlatformFile
+GetIcuDataFileHandle(MemoryMappedFile::Region* out_region);
+
 // Android and html_viewer use a file descriptor passed by browser process to
 // initialize ICU in render processes.
 BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
     PlatformFile data_fd,
-    MemoryMappedFile::Region data_region);
-#endif
+    const MemoryMappedFile::Region& data_region);
+#endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#endif  // !defined(OS_NACL)
 
 // In a test binary, the call above might occur twice.
 BASE_I18N_EXPORT void AllowMultipleInitializeCallsForTesting();
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
index 15b34a3..5512111 100644
--- a/base/i18n/time_formatting.cc
+++ b/base/i18n/time_formatting.cc
@@ -45,6 +45,26 @@
                   static_cast<size_t>(time_string.length()));
 }
 
+icu::SimpleDateFormat CreateSimpleDateFormatter(const char* pattern) {
+  // Generate a locale-dependent format pattern. The generator will take
+  // care of locale-dependent formatting issues like which separator to
+  // use (some locales use '.' instead of ':'), and where to put the am/pm
+  // marker.
+  UErrorCode status = U_ZERO_ERROR;
+  scoped_ptr<icu::DateTimePatternGenerator> generator(
+      icu::DateTimePatternGenerator::createInstance(status));
+  DCHECK(U_SUCCESS(status));
+  icu::UnicodeString generated_pattern =
+      generator->getBestPattern(icu::UnicodeString(pattern), status);
+  DCHECK(U_SUCCESS(status));
+
+  // Then, format the time using the generated pattern.
+  icu::SimpleDateFormat formatter(generated_pattern, status);
+  DCHECK(U_SUCCESS(status));
+
+  return formatter;
+}
+
 }  // namespace
 
 string16 TimeFormatTimeOfDay(const Time& time) {
@@ -55,6 +75,11 @@
   return TimeFormat(formatter.get(), time);
 }
 
+string16 TimeFormatTimeOfDayWithMilliseconds(const Time& time) {
+  icu::SimpleDateFormat formatter = CreateSimpleDateFormatter("HmsSSS");
+  return TimeFormatWithoutAmPm(&formatter, time);
+}
+
 string16 TimeFormatTimeOfDayWithHourClockType(const Time& time,
                                               HourClockType type,
                                               AmPmClockType ampm) {
@@ -65,22 +90,9 @@
     return TimeFormatTimeOfDay(time);
   }
 
-  // Generate a locale-dependent format pattern. The generator will take
-  // care of locale-dependent formatting issues like which separator to
-  // use (some locales use '.' instead of ':'), and where to put the am/pm
-  // marker.
-  UErrorCode status = U_ZERO_ERROR;
-  scoped_ptr<icu::DateTimePatternGenerator> generator(
-      icu::DateTimePatternGenerator::createInstance(status));
-  DCHECK(U_SUCCESS(status));
   const char* base_pattern = (type == k12HourClock ? "ahm" : "Hm");
-  icu::UnicodeString generated_pattern =
-      generator->getBestPattern(icu::UnicodeString(base_pattern), status);
-  DCHECK(U_SUCCESS(status));
+  icu::SimpleDateFormat formatter = CreateSimpleDateFormatter(base_pattern);
 
-  // Then, format the time using the generated pattern.
-  icu::SimpleDateFormat formatter(generated_pattern, status);
-  DCHECK(U_SUCCESS(status));
   if (ampm == kKeepAmPm) {
     return TimeFormat(&formatter, time);
   } else {
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
index 2053c0b..df91f41 100644
--- a/base/i18n/time_formatting.h
+++ b/base/i18n/time_formatting.h
@@ -30,6 +30,10 @@
 // Returns the time of day, e.g., "3:07 PM".
 BASE_I18N_EXPORT string16 TimeFormatTimeOfDay(const Time& time);
 
+// Returns the time of day in 24-hour clock format with millisecond accuracy,
+// e.g., "15:07:30.568"
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDayWithMilliseconds(const Time& time);
+
 // Returns the time of day in the specified hour clock type. e.g.
 // "3:07 PM" (type == k12HourClock, ampm == kKeepAmPm).
 // "3:07"    (type == k12HourClock, ampm == kDropAmPm).
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
index df0c1ed..9385628 100644
--- a/base/i18n/time_formatting_unittest.cc
+++ b/base/i18n/time_formatting_unittest.cc
@@ -12,6 +12,7 @@
 #include "third_party/icu/source/common/unicode/uversion.h"
 #include "third_party/icu/source/i18n/unicode/calendar.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
+#include "third_party/icu/source/i18n/unicode/tzfmt.h"
 
 namespace base {
 namespace {
@@ -21,10 +22,19 @@
   15, 42, 7, 0    // 15:42:07.000
 };
 
-base::string16 GetShortTimeZone() {
+// Returns difference between the local time and GMT formatted as string.
+// This function gets |time| because the difference depends on time,
+// see https://en.wikipedia.org/wiki/Daylight_saving_time for details.
+base::string16 GetShortTimeZone(const Time& time) {
+  UErrorCode status = U_ZERO_ERROR;
   scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+  scoped_ptr<icu::TimeZoneFormat> zone_formatter(
+      icu::TimeZoneFormat::createInstance(icu::Locale::getDefault(), status));
+  EXPECT_TRUE(U_SUCCESS(status));
   icu::UnicodeString name;
-  zone->getDisplayName(true, icu::TimeZone::SHORT, name);
+  zone_formatter->format(UTZFMT_STYLE_SPECIFIC_SHORT, *zone,
+                         static_cast<UDate>(time.ToDoubleT() * 1000), name,
+                         nullptr);
   return base::string16(name.getBuffer(), name.length());
 }
 
@@ -37,9 +47,11 @@
   string16 clock24h(ASCIIToUTF16("15:42"));
   string16 clock12h_pm(ASCIIToUTF16("3:42 PM"));
   string16 clock12h(ASCIIToUTF16("3:42"));
+  string16 clock24h_millis(ASCIIToUTF16("15:42:07.000"));
 
   // The default is 12h clock.
   EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(clock24h_millis, TimeFormatTimeOfDayWithMilliseconds(time));
   EXPECT_EQ(k12HourClock, GetHourClockType());
   // k{Keep,Drop}AmPm should not affect for 24h clock.
   EXPECT_EQ(clock24h,
@@ -70,9 +82,11 @@
   string16 clock24h(ASCIIToUTF16("15:42"));
   string16 clock12h_pm(ASCIIToUTF16("3:42 pm"));
   string16 clock12h(ASCIIToUTF16("3:42"));
+  string16 clock24h_millis(ASCIIToUTF16("15:42:07.000"));
 
   // The default is 24h clock.
   EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(clock24h_millis, TimeFormatTimeOfDayWithMilliseconds(time));
   EXPECT_EQ(k24HourClock, GetHourClockType());
   // k{Keep,Drop}AmPm should not affect for 24h clock.
   EXPECT_EQ(clock24h,
@@ -139,7 +153,7 @@
 
   EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"),
             TimeFormatShortDateAndTime(time));
-  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(),
+  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(time),
             TimeFormatShortDateAndTimeWithTimeZone(time));
 
   EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"),
@@ -160,7 +174,7 @@
   EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time));
   EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07"),
             TimeFormatShortDateAndTime(time));
-  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(),
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(time),
             TimeFormatShortDateAndTimeWithTimeZone(time));
   EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
             TimeFormatFriendlyDateAndTime(time));
diff --git a/base/ios/crb_protocol_observers_unittest.mm b/base/ios/crb_protocol_observers_unittest.mm
index 5f11051..b8cf423 100644
--- a/base/ios/crb_protocol_observers_unittest.mm
+++ b/base/ios/crb_protocol_observers_unittest.mm
@@ -4,6 +4,7 @@
 
 #import "base/ios/crb_protocol_observers.h"
 #include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/mac/scoped_nsobject.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -36,10 +37,9 @@
 @end
 
 @interface TestMutateObserver : TestCompleteObserver
-
 - (instancetype)initWithObserver:(CRBProtocolObservers*)observer
     NS_DESIGNATED_INITIALIZER;
-
+- (instancetype)init NS_UNAVAILABLE;
 @end
 
 namespace {
@@ -266,6 +266,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)mutateByAddingObserver:(id<TestObserver>)observer {
   [_observers addObserver:observer];
 }
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm
index 1234562..4af8234 100644
--- a/base/ios/device_util.mm
+++ b/base/ios/device_util.mm
@@ -59,7 +59,7 @@
   std::string platform;
   size_t size = 0;
   sysctlbyname("hw.machine", NULL, &size, NULL, 0);
-  sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
+  sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0);
   return platform;
 }
 
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
index d9d7e19..688fbf3 100644
--- a/base/ios/ios_util.h
+++ b/base/ios/ios_util.h
@@ -14,6 +14,9 @@
 // Returns whether the operating system is iOS 8 or later.
 BASE_EXPORT bool IsRunningOnIOS8OrLater();
 
+// Returns whether the operating system is iOS 9 or later.
+BASE_EXPORT bool IsRunningOnIOS9OrLater();
+
 // Returns whether the operating system is at the given version or later.
 BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
 
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
index ca0a24d..d920045 100644
--- a/base/ios/ios_util.mm
+++ b/base/ios/ios_util.mm
@@ -20,10 +20,15 @@
 namespace base {
 namespace ios {
 
+// When dropping iOS7 support, also address issues listed in crbug.com/502968.
 bool IsRunningOnIOS8OrLater() {
   return IsRunningOnOrLater(8, 0, 0);
 }
 
+bool IsRunningOnIOS9OrLater() {
+  return IsRunningOnOrLater(9, 0, 0);
+}
+
 bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) {
   static const int32* current_version = OSVersionAsArray();
   int32 version[] = { major, minor, bug_fix };
diff --git a/base/ios/ns_error_util.h b/base/ios/ns_error_util.h
new file mode 100644
index 0000000..1012292
--- /dev/null
+++ b/base/ios/ns_error_util.h
@@ -0,0 +1,25 @@
+// 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_IOS_NS_ERROR_UTIL_H_
+#define BASE_IOS_NS_ERROR_UTIL_H_
+
+@class NSError;
+
+namespace base {
+namespace ios {
+
+// Iterates through |error|'s underlying errors and returns the first error for
+// which there is no underlying error.
+NSError* GetFinalUnderlyingErrorFromError(NSError* error);
+
+// Returns a copy of |original_error| with |underlying_error| appended to the
+// end of its underlying error chain.
+NSError* ErrorWithAppendedUnderlyingError(NSError* original_error,
+                                          NSError* underlying_error);
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_NS_ERROR_UTIL_H_
diff --git a/base/ios/ns_error_util.mm b/base/ios/ns_error_util.mm
new file mode 100644
index 0000000..c44d9ee
--- /dev/null
+++ b/base/ios/ns_error_util.mm
@@ -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.
+
+#import "base/ios/ns_error_util.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace base {
+namespace ios {
+
+namespace {
+// Iterates through |error|'s underlying errors and returns them in an array.
+NSArray* GetFullErrorChainForError(NSError* error) {
+  NSMutableArray* error_chain = [NSMutableArray array];
+  NSError* current_error = error;
+  while (current_error) {
+    DCHECK([current_error isKindOfClass:[NSError class]]);
+    [error_chain addObject:current_error];
+    current_error = current_error.userInfo[NSUnderlyingErrorKey];
+  }
+  return error_chain;
+}
+}  // namespace
+
+NSError* GetFinalUnderlyingErrorFromError(NSError* error) {
+  DCHECK(error);
+  return [GetFullErrorChainForError(error) lastObject];
+}
+
+NSError* ErrorWithAppendedUnderlyingError(NSError* original_error,
+                                          NSError* underlying_error) {
+  DCHECK(original_error);
+  DCHECK(underlying_error);
+  NSArray* error_chain = GetFullErrorChainForError(original_error);
+  NSError* current_error = underlying_error;
+  for (NSInteger idx = error_chain.count - 1; idx >= 0; --idx) {
+    NSError* error = error_chain[idx];
+    scoped_nsobject<NSMutableDictionary> user_info(
+        [error.userInfo mutableCopy]);
+    [user_info setObject:current_error forKey:NSUnderlyingErrorKey];
+    current_error = [NSError errorWithDomain:error.domain
+                                        code:error.code
+                                    userInfo:user_info];
+  }
+  return current_error;
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index 4d79be3..fc972ce 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -31,7 +31,7 @@
 // optimization avoids about 2/3rds of string memory copies. The constructor
 // takes ownership of the input string. The real root value is Swap()ed into
 // the new instance.
-class DictionaryHiddenRootValue : public base::DictionaryValue {
+class DictionaryHiddenRootValue : public DictionaryValue {
  public:
   DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) {
     DCHECK(root->IsType(Value::TYPE_DICTIONARY));
@@ -43,7 +43,7 @@
 
     // First deep copy to convert JSONStringValue to std::string and swap that
     // copy with |other|, which contains the new contents of |this|.
-    scoped_ptr<base::DictionaryValue> copy(DeepCopy());
+    scoped_ptr<DictionaryValue> copy(DeepCopy());
     copy->Swap(other);
 
     // Then erase the contents of the current dictionary and swap in the
@@ -81,7 +81,7 @@
   DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
 };
 
-class ListHiddenRootValue : public base::ListValue {
+class ListHiddenRootValue : public ListValue {
  public:
   ListHiddenRootValue(std::string* json, Value* root) : json_(json) {
     DCHECK(root->IsType(Value::TYPE_LIST));
@@ -93,7 +93,7 @@
 
     // First deep copy to convert JSONStringValue to std::string and swap that
     // copy with |other|, which contains the new contents of |this|.
-    scoped_ptr<base::ListValue> copy(DeepCopy());
+    scoped_ptr<ListValue> copy(DeepCopy());
     copy->Swap(other);
 
     // Then erase the contents of the current list and swap in the new contents,
@@ -130,14 +130,12 @@
 // A variant on StringValue that uses StringPiece instead of copying the string
 // into the Value. This can only be stored in a child of hidden root (above),
 // otherwise the referenced string will not be guaranteed to outlive it.
-class JSONStringValue : public base::Value {
+class JSONStringValue : public Value {
  public:
-  explicit JSONStringValue(const base::StringPiece& piece)
-      : Value(TYPE_STRING),
-        string_piece_(piece) {
-  }
+  explicit JSONStringValue(const StringPiece& piece)
+      : Value(TYPE_STRING), string_piece_(piece) {}
 
-  // Overridden from base::Value:
+  // Overridden from Value:
   bool GetAsString(std::string* out_value) const override {
     string_piece_.CopyToString(out_value);
     return true;
@@ -157,7 +155,7 @@
 
  private:
   // The location in the original input stream.
-  base::StringPiece string_piece_;
+  StringPiece string_piece_;
 
   DISALLOW_COPY_AND_ASSIGN(JSONStringValue);
 };
@@ -776,11 +774,17 @@
 
     uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
                                                 code_unit16_low);
+    if (!IsValidCharacter(code_point))
+      return false;
+
     offset = 0;
     CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
   } else {
     // Not a surrogate.
     DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+    if (!IsValidCharacter(code_unit16_high))
+      return false;
+
     CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
   }
 
@@ -789,6 +793,8 @@
 }
 
 void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+  DCHECK(IsValidCharacter(point));
+
   // Anything outside of the basic ASCII plane will need to be decoded from
   // int32 to a multi-byte sequence.
   if (point < kExtendedASCIIStart) {
@@ -872,7 +878,7 @@
     return new FundamentalValue(num_int);
 
   double num_double;
-  if (base::StringToDouble(num_string.as_string(), &num_double) &&
+  if (StringToDouble(num_string.as_string(), &num_double) &&
       std::isfinite(num_double)) {
     return new FundamentalValue(num_double);
   }
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
index f776ddf..d88f9ea 100644
--- a/base/json/json_parser_unittest.cc
+++ b/base/json/json_parser_unittest.cc
@@ -313,5 +313,13 @@
   EXPECT_TRUE(root.get()) << error_message;
 }
 
+TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) {
+  // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
+  // characters.
+  EXPECT_FALSE(JSONReader::Read("[\"\\ufdd0\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\ufffe\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\ud83f\\udffe\"]"));
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/logging.cc b/base/logging.cc
index 1a2f774..7654e7f 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -521,6 +521,12 @@
   Init(file, line);
 }
 
+LogMessage::LogMessage(const char* file, int line, const char* condition)
+    : severity_(LOG_FATAL), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << condition << ". ";
+}
+
 LogMessage::LogMessage(const char* file, int line, std::string* result)
     : severity_(LOG_FATAL), file_(file), line_(line) {
   Init(file, line);
diff --git a/base/logging.h b/base/logging.h
index ea096d1..adc8fb6 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -436,7 +436,7 @@
 #if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
 
 // Make all CHECK functions discard their log strings to reduce code
-// bloat for official release builds.
+// bloat for official release builds (except Android).
 
 // TODO(akalin): This would be more valuable if there were some way to
 // remove BreakDebugger() from the backtrace, perhaps by turning it
@@ -470,9 +470,10 @@
 
 #else  // _PREFAST_
 
-#define CHECK(condition)                       \
-  LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
-  << "Check failed: " #condition ". "
+// Do as much work as possible out of line to reduce inline code size.
+#define CHECK(condition)                                                    \
+  LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
+              !(condition))
 
 #define PCHECK(condition)                       \
   LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
@@ -727,6 +728,9 @@
   // Used for LOG(severity).
   LogMessage(const char* file, int line, LogSeverity severity);
 
+  // Used for CHECK().  Implied severity = LOG_FATAL.
+  LogMessage(const char* file, int line, const char* condition);
+
   // Used for CHECK_EQ(), etc. Takes ownership of the given string.
   // Implied severity = LOG_FATAL.
   LogMessage(const char* file, int line, std::string* result);
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
index 4aba972..a3fc32f 100644
--- a/base/mac/OWNERS
+++ b/base/mac/OWNERS
@@ -1,14 +1,2 @@
 mark@chromium.org
 thakis@chromium.org
-
-# sdk_forward_declarations.[h|mm] will likely need to be modified by Cocoa
-# developers in general; keep in sync with OWNERS of //chrome/browser/ui/cocoa.
-per-file sdk_forward_declarations.*=asvitkine@chromium.org
-per-file sdk_forward_declarations.*=avi@chromium.org
-per-file sdk_forward_declarations.*=groby@chromium.org
-per-file sdk_forward_declarations.*=jeremy@chromium.org
-per-file sdk_forward_declarations.*=mark@chromium.org
-per-file sdk_forward_declarations.*=rohitrao@chromium.org
-per-file sdk_forward_declarations.*=rsesek@chromium.org
-per-file sdk_forward_declarations.*=shess@chromium.org
-per-file sdk_forward_declarations.*=thakis@chromium.org
diff --git a/base/mac/call_with_eh_frame.cc b/base/mac/call_with_eh_frame.cc
new file mode 100644
index 0000000..8ea6f75
--- /dev/null
+++ b/base/mac/call_with_eh_frame.cc
@@ -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.
+
+#include "base/mac/call_with_eh_frame.h"
+
+#include <unwind.h>
+
+#include "build/build_config.h"
+
+namespace base {
+namespace mac {
+
+_Unwind_Reason_Code CxxPersonalityRoutine(
+    int version,
+    _Unwind_Action actions,
+    uint64_t exceptionClass,
+    struct _Unwind_Exception* exceptionObject,
+    struct _Unwind_Context* context) {
+  // Tell libunwind that this is the end of the stack. When it encounters the
+  // CallWithEHFrame, it will stop searching for an exception handler. The
+  // result is that no exception handler has been found higher on the stack,
+  // and any that are lower on the stack (e.g. in CFRunLoopRunSpecific), will
+  // now be skipped. Since this is reporting the end of the stack, and no
+  // exception handler will have been found, std::terminate() will be called.
+  return _URC_END_OF_STACK;
+}
+
+#if defined(OS_IOS)
+// No iOS assembly implementation exists, so just call the block directly.
+void CallWithEHFrame(void (^block)(void)) {
+  block();
+}
+#endif
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/call_with_eh_frame.h b/base/mac/call_with_eh_frame.h
new file mode 100644
index 0000000..1f7d5e0
--- /dev/null
+++ b/base/mac/call_with_eh_frame.h
@@ -0,0 +1,26 @@
+// 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_MAC_CALL_WITH_EH_FRAME_H_
+#define BASE_MAC_CALL_WITH_EH_FRAME_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// Invokes the specified block in a stack frame with a special exception
+// handler. This function creates an exception handling stack frame that
+// specifies a custom C++ exception personality routine, which terminates the
+// search for an exception handler at this frame.
+//
+// The purpose of this function is to prevent a try/catch statement in system
+// libraries, acting as a global exception handler, from handling exceptions
+// in such a way that disrupts the generation of useful stack traces.
+void BASE_EXPORT CallWithEHFrame(void (^block)(void));
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_CALL_WITH_EH_FRAME_H_
diff --git a/base/mac/call_with_eh_frame_asm.S b/base/mac/call_with_eh_frame_asm.S
new file mode 100644
index 0000000..0e399cf
--- /dev/null
+++ b/base/mac/call_with_eh_frame_asm.S
@@ -0,0 +1,89 @@
+// 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.
+
+// base::mac::CallWithEHFrame(void () block_pointer)
+#define CALL_WITH_EH_FRAME __ZN4base3mac15CallWithEHFrameEU13block_pointerFvvE
+
+  .section __TEXT,__text,regular,pure_instructions
+#if !defined(COMPONENT_BUILD)
+  .private_extern CALL_WITH_EH_FRAME
+#endif
+  .globl CALL_WITH_EH_FRAME
+  .align 4
+CALL_WITH_EH_FRAME:
+
+  .cfi_startproc
+
+  // Configure the C++ exception handler personality routine. Normally the
+  // compiler would emit ___gxx_personality_v0 here. The purpose of this
+  // function is to use a custom personality routine.
+  .cfi_personality 155, __ZN4base3mac21CxxPersonalityRoutineEi14_Unwind_ActionyP17_Unwind_ExceptionP15_Unwind_Context
+  .cfi_lsda 16, CallWithEHFrame_exception_table
+
+Lfunction_start:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+
+  // Load the function pointer from the block descriptor.
+  movq 16(%rdi), %rax
+
+  // Execute the block in the context of a C++ try{}.
+Ltry_start:
+  callq *%rax
+Ltry_end:
+  popq %rbp
+  ret
+
+  // Landing pad for the exception handler. This should never be called, since
+  // the personality routine will stop the search for an exception handler,
+  // which will cause the runtime to invoke the default terminate handler.
+Lcatch:
+  movq %rax, %rdi
+  callq ___cxa_begin_catch  // The ABI requires a call to the catch handler.
+  ud2  // In the event this is called, make it fatal.
+
+Lfunction_end:
+  .cfi_endproc
+
+// The C++ exception table that is used to identify this frame as an
+// exception handler. See http://llvm.org/docs/ExceptionHandling.html and
+// http://mentorembedded.github.io/cxx-abi/exceptions.pdf.
+  .section __TEXT,__gcc_except_tab
+  .align 2
+CallWithEHFrame_exception_table:
+  .byte 255  // DW_EH_PE_omit
+  .byte 155  // DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4
+  .asciz "\242\200\200"  // LE int128 for the number of bytes in this table.
+  .byte 3  // DW_EH_PE_udata4
+  .byte 26  // Callsite table length.
+
+// First callsite.
+CS1_begin = Ltry_start - Lfunction_start
+  .long CS1_begin
+CS1_end = Ltry_end - Ltry_start
+  .long CS1_end
+
+// First landing pad.
+LP1 = Lcatch - Lfunction_start
+  .long LP1
+  .byte 1  // Action record.
+
+// Second callsite.
+CS2_begin = Ltry_end - Lfunction_start
+  .long CS2_begin
+CS2_end = Lfunction_end - Ltry_end
+  .long CS2_end
+
+// Second landing pad (none).
+  .long 0
+  .byte 0  // No action.
+
+// Action table.
+  .byte 1  // Action record 1.
+  .byte 0  // No further action to take.
+  .long 0  // No type filter for this catch(){} clause.
+  .align 2
diff --git a/base/mac/call_with_eh_frame_unittest.mm b/base/mac/call_with_eh_frame_unittest.mm
new file mode 100644
index 0000000..663dae7
--- /dev/null
+++ b/base/mac/call_with_eh_frame_unittest.mm
@@ -0,0 +1,51 @@
+// 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/mac/call_with_eh_frame.h"
+
+#import <Foundation/Foundation.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace mac {
+namespace {
+
+class CallWithEHFrameTest : public testing::Test {
+ protected:
+  void ThrowException() { [NSArray arrayWithObject:nil]; }
+};
+
+// Catching from within the EHFrame is allowed.
+TEST_F(CallWithEHFrameTest, CatchExceptionHigher) {
+  bool __block saw_exception = false;
+  base::mac::CallWithEHFrame(^{
+    @try {
+      ThrowException();
+    } @catch (NSException* exception) {
+      saw_exception = true;
+    }
+  });
+  EXPECT_TRUE(saw_exception);
+}
+
+// Trying to catch an exception outside the EHFrame is blocked.
+TEST_F(CallWithEHFrameTest, CatchExceptionLower) {
+  auto catch_exception_lower = ^{
+    bool saw_exception = false;
+    @try {
+      base::mac::CallWithEHFrame(^{
+        ThrowException();
+      });
+    } @catch (NSException* exception) {
+      saw_exception = true;
+    }
+    ASSERT_FALSE(saw_exception);
+  };
+  EXPECT_DEATH(catch_exception_lower(), "");
+}
+
+}  // namespace
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index f8ffa97..af52667 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -147,6 +147,10 @@
 BASE_EXPORT bool IsOSYosemite();
 BASE_EXPORT bool IsOSYosemiteOrLater();
 
+// El Capitan is Mac OS X 10.11, Darwin 15.
+BASE_EXPORT bool IsOSElCapitan();
+BASE_EXPORT bool IsOSElCapitanOrLater();
+
 // This should be infrequently used. It only makes sense to use this to avoid
 // codepaths that are very likely to break on future (unreleased, untested,
 // unborn) OS releases, or to log when the OS is newer than any known version.
@@ -157,6 +161,9 @@
 inline bool IsOSLionOrEarlier() { return !IsOSMountainLionOrLater(); }
 inline bool IsOSMountainLionOrEarlier() { return !IsOSMavericksOrLater(); }
 inline bool IsOSMavericksOrEarlier() { return !IsOSYosemiteOrLater(); }
+inline bool IsOSYosemiteOrEarlier() {
+  return !IsOSElCapitanOrLater();
+}
 
 // When the deployment target is set, the code produced cannot run on earlier
 // OS releases. That enables some of the IsOS* family to be implemented as
@@ -213,6 +220,22 @@
 inline bool IsOSLaterThanYosemite_DontCallThis() { return true; }
 #endif
 
+#if defined(MAC_OS_X_VERSION_10_11) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_11
+inline bool IsOSElCapitanOrLater() {
+  return true;
+}
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11
+inline bool IsOSElCapitan() {
+  return false;
+}
+#endif
+
 // Retrieve the system's model identifier string from the IOKit registry:
 // for example, "MacPro4,1", "MacBookPro6,1". Returns empty string upon
 // failure.
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index bdf45de..e1e15dc 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -483,6 +483,7 @@
   MOUNTAIN_LION_MINOR_VERSION = 8,
   MAVERICKS_MINOR_VERSION = 9,
   YOSEMITE_MINOR_VERSION = 10,
+  EL_CAPITAN_MINOR_VERSION = 11,
 };
 
 }  // namespace
@@ -547,6 +548,18 @@
 }
 #endif
 
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11)
+bool IsOSElCapitan() {
+  return MacOSXMinorVersion() == EL_CAPITAN_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_11)
+bool IsOSElCapitanOrLater() {
+  return MacOSXMinorVersion() >= EL_CAPITAN_MINOR_VERSION;
+}
+#endif
+
 std::string GetModelIdentifier() {
   std::string return_string;
   ScopedIOObject<io_service_t> platform_expert(
diff --git a/base/macros.h b/base/macros.h
index 0325e74..53b3926 100644
--- a/base/macros.h
+++ b/base/macros.h
@@ -41,7 +41,7 @@
 // that wants to prevent anyone from instantiating it. This is
 // especially useful for classes containing only static methods.
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName();                                    \
+  TypeName() = delete;                           \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 
 // The arraysize(arr) macro returns the # of elements in an array arr.
diff --git a/base/memory/BUILD.gn b/base/memory/BUILD.gn
index c53cc05..1f1d3f2 100644
--- a/base/memory/BUILD.gn
+++ b/base/memory/BUILD.gn
@@ -35,6 +35,9 @@
     "scoped_vector.h",
     "shared_memory.h",
     "shared_memory_android.cc",
+    "shared_memory_handle.h",
+    "shared_memory_handle_mac.cc",
+    "shared_memory_mac.cc",
     "shared_memory_nacl.cc",
     "shared_memory_posix.cc",
     "shared_memory_win.cc",
@@ -54,6 +57,10 @@
     sources -= [ "shared_memory_nacl.cc" ]
   }
 
+  if (is_mac) {
+    sources -= [ "shared_memory_posix.cc" ]
+  }
+
   if (is_android) {
     deps = [
       "//third_party/ashmem",
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
index 6a109e8..d278a44 100644
--- a/base/memory/ref_counted_delete_on_message_loop.h
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -8,8 +8,6 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-// TODO(ricea): Remove the following include once all callers have been fixed.
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/single_thread_task_runner.h"
 
 namespace base {
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
index 173ea5a..e1e5c72 100644
--- a/base/memory/scoped_vector.h
+++ b/base/memory/scoped_vector.h
@@ -106,6 +106,10 @@
     return v_.insert(position, x);
   }
 
+  iterator insert(iterator position, scoped_ptr<T> x) {
+    return v_.insert(position, x.release());
+  }
+
   // Lets the ScopedVector take ownership of elements in [first,last).
   template<typename InputIterator>
   void insert(iterator position, InputIterator first, InputIterator last) {
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index 008bb01..4326758 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -17,6 +17,7 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/memory/shared_memory_handle.h"
 #include "base/process/process_handle.h"
 
 #if defined(OS_POSIX)
@@ -29,14 +30,6 @@
 
 class FilePath;
 
-// SharedMemoryHandle is a platform specific type which represents
-// the underlying OS handle to a shared memory segment.
-#if defined(OS_WIN)
-typedef HANDLE SharedMemoryHandle;
-#elif defined(OS_POSIX)
-typedef FileDescriptor SharedMemoryHandle;
-#endif
-
 // Options for creating a shared memory object.
 struct SharedMemoryCreateOptions {
   SharedMemoryCreateOptions()
@@ -89,12 +82,13 @@
   // only affects how the SharedMemory will be mmapped.  Use
   // ShareReadOnlyToProcess to drop permissions.  TODO(jln,jyasskin): DCHECK
   // that |read_only| matches the permissions of the handle.
-  SharedMemory(SharedMemoryHandle handle, bool read_only);
+  SharedMemory(const SharedMemoryHandle& handle, bool read_only);
 
   // Create a new SharedMemory object from an existing, open
   // shared memory file that was created by a remote process and not shared
   // to the current process.
-  SharedMemory(SharedMemoryHandle handle, bool read_only,
+  SharedMemory(const SharedMemoryHandle& handle,
+               bool read_only,
                ProcessHandle process);
 
   // Closes any open files.
@@ -257,27 +251,11 @@
     return ShareToProcessCommon(process, new_handle, true, SHARE_CURRENT_MODE);
   }
 
-  // DEPRECATED (crbug.com/345734):
-  // Locks the shared memory.
-  //
-  // WARNING: on POSIX the memory locking primitive only works across
-  // processes, not across threads.  The LockDeprecated method is not currently
-  // used in inner loops, so we protect against multiple threads in a
-  // critical section using a class global lock.
-  void LockDeprecated();
-
-  // DEPRECATED (crbug.com/345734):
-  // Releases the shared memory lock.
-  void UnlockDeprecated();
-
  private:
-#if defined(OS_POSIX) && !defined(OS_NACL)
-#if !defined(OS_ANDROID)
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID)
   bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
   bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
-#endif
-  void LockOrUnlockCommon(int function);
-#endif  // defined(OS_POSIX) && !defined(OS_NACL)
+#endif  // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID)
   enum ShareMode {
     SHARE_READONLY,
     SHARE_CURRENT_MODE,
@@ -298,32 +276,9 @@
   void*              memory_;
   bool               read_only_;
   size_t             requested_size_;
-#if !defined(OS_POSIX)
-  HANDLE             lock_;
-#endif
 
   DISALLOW_COPY_AND_ASSIGN(SharedMemory);
 };
-
-// DEPRECATED (crbug.com/345734):
-// A helper class that acquires the shared memory lock while
-// the SharedMemoryAutoLockDeprecated is in scope.
-class SharedMemoryAutoLockDeprecated {
- public:
-  explicit SharedMemoryAutoLockDeprecated(SharedMemory* shared_memory)
-      : shared_memory_(shared_memory) {
-    shared_memory_->LockDeprecated();
-  }
-
-  ~SharedMemoryAutoLockDeprecated() {
-    shared_memory_->UnlockDeprecated();
-  }
-
- private:
-  SharedMemory* shared_memory_;
-  DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLockDeprecated);
-};
-
 }  // namespace base
 
 #endif  // BASE_MEMORY_SHARED_MEMORY_H_
diff --git a/base/memory/shared_memory_handle.h b/base/memory/shared_memory_handle.h
new file mode 100644
index 0000000..7af8729
--- /dev/null
+++ b/base/memory/shared_memory_handle.h
@@ -0,0 +1,97 @@
+// 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_MEMORY_SHARED_MEMORY_HANDLE_H_
+#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include <sys/types.h>
+#include "base/base_export.h"
+#include "base/file_descriptor_posix.h"
+#include "base/macros.h"
+#elif defined(OS_POSIX)
+#include <sys/types.h>
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace base {
+
+class Pickle;
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+#if defined(OS_WIN)
+typedef HANDLE SharedMemoryHandle;
+#elif defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+typedef FileDescriptor SharedMemoryHandle;
+#else
+class BASE_EXPORT SharedMemoryHandle {
+ public:
+  enum Type {
+    // Indicates that the SharedMemoryHandle is backed by a POSIX fd.
+    POSIX,
+    // Indicates that the SharedMemoryHandle is backed by the Mach primitive
+    // "memory object".
+    MACH,
+  };
+
+  // The format that should be used to transmit |Type| over the wire.
+  typedef int TypeWireFormat;
+
+  // The default constructor returns an invalid SharedMemoryHandle.
+  SharedMemoryHandle();
+
+  // Constructs a SharedMemoryHandle backed by the components of a
+  // FileDescriptor. The newly created instance has the same ownership semantics
+  // as base::FileDescriptor. This typically means that the SharedMemoryHandle
+  // takes ownership of the |fd| if |auto_close| is true. Unfortunately, it's
+  // common for existing code to make shallow copies of SharedMemoryHandle, and
+  // the one that is finally passed into a base::SharedMemory is the one that
+  // "consumes" the fd.
+  explicit SharedMemoryHandle(const base::FileDescriptor& file_descriptor);
+  SharedMemoryHandle(int fd, bool auto_close);
+
+  // Standard copy constructor. The new instance shares the underlying OS
+  // primitives.
+  SharedMemoryHandle(const SharedMemoryHandle& handle);
+
+  // Standard assignment operator. The updated instance shares the underlying
+  // OS primitives.
+  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
+
+  // Duplicates the underlying OS resources.
+  SharedMemoryHandle Duplicate() const;
+
+  // Comparison operators.
+  bool operator==(const SharedMemoryHandle& handle) const;
+  bool operator!=(const SharedMemoryHandle& handle) const;
+
+  // Returns the type.
+  Type GetType() const;
+
+  // Whether the underlying OS primitive is valid.
+  bool IsValid() const;
+
+  // Sets the POSIX fd backing the SharedMemoryHandle. Requires that the
+  // SharedMemoryHandle be backed by a POSIX fd.
+  void SetFileHandle(int fd, bool auto_close);
+
+  // This method assumes that the SharedMemoryHandle is backed by a POSIX fd.
+  // This is eventually no longer going to be true, so please avoid adding new
+  // uses of this method.
+  const FileDescriptor GetFileDescriptor() const;
+
+ private:
+  Type type_;
+  FileDescriptor file_descriptor_;
+};
+#endif
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
diff --git a/base/memory/shared_memory_handle_mac.cc b/base/memory/shared_memory_handle_mac.cc
new file mode 100644
index 0000000..86f5c54
--- /dev/null
+++ b/base/memory/shared_memory_handle_mac.cc
@@ -0,0 +1,86 @@
+// 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/memory/shared_memory_handle.h"
+
+#include <unistd.h>
+
+#include "base/posix/eintr_wrapper.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+namespace base {
+
+static_assert(sizeof(SharedMemoryHandle::Type) <=
+                  sizeof(SharedMemoryHandle::TypeWireFormat),
+              "Size of enum SharedMemoryHandle::Type exceeds size of type "
+              "transmitted over wire.");
+
+SharedMemoryHandle::SharedMemoryHandle() : type_(POSIX), file_descriptor_() {}
+
+SharedMemoryHandle::SharedMemoryHandle(
+    const base::FileDescriptor& file_descriptor)
+    : type_(POSIX), file_descriptor_(file_descriptor) {}
+
+SharedMemoryHandle::SharedMemoryHandle(int fd, bool auto_close)
+    : type_(POSIX), file_descriptor_(fd, auto_close) {}
+
+SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle)
+    : type_(handle.type_), file_descriptor_(handle.file_descriptor_) {}
+
+SharedMemoryHandle& SharedMemoryHandle::operator=(
+    const SharedMemoryHandle& handle) {
+  if (this == &handle)
+    return *this;
+
+  type_ = handle.type_;
+  file_descriptor_ = handle.file_descriptor_;
+  return *this;
+}
+
+bool SharedMemoryHandle::operator==(const SharedMemoryHandle& handle) const {
+  // Invalid handles are always equal, even if they have different types.
+  if (!IsValid() && !handle.IsValid())
+    return true;
+
+  return type_ == handle.type_ && file_descriptor_ == handle.file_descriptor_;
+}
+
+bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
+  return !(*this == handle);
+}
+
+SharedMemoryHandle::Type SharedMemoryHandle::GetType() const {
+  return type_;
+}
+
+bool SharedMemoryHandle::IsValid() const {
+  switch (type_) {
+    case POSIX:
+      return file_descriptor_.fd >= 0;
+    case MACH:
+      return false;
+  }
+}
+
+void SharedMemoryHandle::SetFileHandle(int fd, bool auto_close) {
+  DCHECK_EQ(type_, POSIX);
+  file_descriptor_.fd = fd;
+  file_descriptor_.auto_close = auto_close;
+}
+
+const FileDescriptor SharedMemoryHandle::GetFileDescriptor() const {
+  DCHECK_EQ(type_, POSIX);
+  return file_descriptor_;
+}
+
+SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
+  DCHECK_EQ(type_, POSIX);
+  int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd));
+  if (duped_handle < 0)
+    return SharedMemoryHandle();
+  return SharedMemoryHandle(duped_handle, true);
+}
+
+}  // namespace base
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
diff --git a/base/memory/shared_memory_mac.cc b/base/memory/shared_memory_mac.cc
new file mode 100644
index 0000000..8d8a164
--- /dev/null
+++ b/base/memory/shared_memory_mac.cc
@@ -0,0 +1,460 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
+#include "base/process/process_metrics.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/scoped_generic.h"
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif  // OS_MACOSX
+
+namespace base {
+
+namespace {
+
+struct ScopedPathUnlinkerTraits {
+  static FilePath* InvalidValue() { return nullptr; }
+
+  static void Free(FilePath* path) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::Unlink"));
+    if (unlink(path->value().c_str()))
+      PLOG(WARNING) << "unlink";
+  }
+};
+
+// Unlinks the FilePath when the object is destroyed.
+typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
+
+// Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
+// with the fdopened FILE. |readonly_fd| is populated with the opened fd if
+// options.share_read_only is true. |path| is populated with the location of
+// the file before it was unlinked.
+// Returns false if there's an unhandled failure.
+bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
+                                 ScopedFILE* fp,
+                                 ScopedFD* readonly_fd,
+                                 FilePath* path) {
+  // It doesn't make sense to have a open-existing private piece of shmem
+  DCHECK(!options.open_existing_deprecated);
+  // Q: Why not use the shm_open() etc. APIs?
+  // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+  FilePath directory;
+  ScopedPathUnlinker path_unlinker;
+  if (GetShmemTempDir(options.executable, &directory)) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::OpenTemporaryFile"));
+    fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
+
+    // Deleting the file prevents anyone else from mapping it in (making it
+    // private), and prevents the need for cleanup (once the last fd is
+    // closed, it is truly freed).
+    if (*fp)
+      path_unlinker.reset(path);
+  }
+
+  if (*fp) {
+    if (options.share_read_only) {
+      // TODO(erikchen): Remove ScopedTracker below once
+      // http://crbug.com/466437 is fixed.
+      tracked_objects::ScopedTracker tracking_profile(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+              "466437 SharedMemory::Create::OpenReadonly"));
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
+      if (!readonly_fd->is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
+        fp->reset();
+        return false;
+      }
+    }
+  }
+  return true;
+}
+}
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {}
+
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
+    : mapped_file_(GetFdFromSharedMemoryHandle(handle)),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {}
+
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(GetFdFromSharedMemoryHandle(handle)),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  // We don't handle this case yet (note the ignored parameter); let's die if
+  // someone comes calling.
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.IsValid();
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK_GE(GetFdFromSharedMemoryHandle(handle), 0);
+  if (close(GetFdFromSharedMemoryHandle(handle)) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  return base::GetMaxFds();
+}
+
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.Duplicate();
+}
+
+// static
+int SharedMemory::GetFdFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.GetFileDescriptor().fd;
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+// static
+int SharedMemory::GetSizeFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  struct stat st;
+  if (fstat(GetFdFromSharedMemoryHandle(handle), &st) != 0)
+    return -1;
+  return st.st_size;
+}
+
+// Chromium mostly only uses the unique/private shmem as specified by
+// "name == L"". The exception is in the StatsTable.
+// TODO(jrg): there is no way to "clean up" all unused named shmem if
+// we restart from a crash.  (That isn't a new problem, but it is a problem.)
+// In case we want to delete it later, it may be useful to save the value
+// of mem_filename after FilePathForMemoryName().
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+  // is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("466437 SharedMemory::Create::Start"));
+  DCHECK_EQ(-1, mapped_file_);
+  if (options.size == 0)
+    return false;
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  ScopedFILE fp;
+  bool fix_size = true;
+  ScopedFD readonly_fd;
+
+  FilePath path;
+  if (options.name_deprecated == NULL || options.name_deprecated->empty()) {
+    bool result =
+        CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
+    if (!result)
+      return false;
+  } else {
+    if (!FilePathForMemoryName(*options.name_deprecated, &path))
+      return false;
+
+    // Make sure that the file is opened without any permission
+    // to other users on the system.
+    const mode_t kOwnerOnly = S_IRUSR | S_IWUSR;
+
+    // First, try to create the file.
+    int fd = HANDLE_EINTR(
+        open(path.value().c_str(), O_RDWR | O_CREAT | O_EXCL, kOwnerOnly));
+    if (fd == -1 && options.open_existing_deprecated) {
+      // If this doesn't work, try and open an existing file in append mode.
+      // Opening an existing file in a world writable directory has two main
+      // security implications:
+      // - Attackers could plant a file under their control, so ownership of
+      //   the file is checked below.
+      // - Attackers could plant a symbolic link so that an unexpected file
+      //   is opened, so O_NOFOLLOW is passed to open().
+      fd = HANDLE_EINTR(
+          open(path.value().c_str(), O_RDWR | O_APPEND | O_NOFOLLOW));
+
+      // Check that the current user owns the file.
+      // If uid != euid, then a more complex permission model is used and this
+      // API is not appropriate.
+      const uid_t real_uid = getuid();
+      const uid_t effective_uid = geteuid();
+      struct stat sb;
+      if (fd >= 0 && (fstat(fd, &sb) != 0 || sb.st_uid != real_uid ||
+                      sb.st_uid != effective_uid)) {
+        LOG(ERROR) << "Invalid owner when opening existing shared memory file.";
+        close(fd);
+        return false;
+      }
+
+      // An existing file was opened, so its size should not be fixed.
+      fix_size = false;
+    }
+
+    if (options.share_read_only) {
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+      if (!readonly_fd.is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+        close(fd);
+        fd = -1;
+        return false;
+      }
+    }
+    if (fd >= 0) {
+      // "a+" is always appropriate: if it's a new file, a+ is similar to w+.
+      fp.reset(fdopen(fd, "a+"));
+    }
+  }
+  if (fp && fix_size) {
+    // Get current size.
+    struct stat stat;
+    if (fstat(fileno(fp.get()), &stat) != 0)
+      return false;
+    const size_t current_size = stat.st_size;
+    if (current_size != options.size) {
+      if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
+        return false;
+    }
+    requested_size_ = options.size;
+  }
+  if (fp == NULL) {
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    return false;
+  }
+
+  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+}
+
+// Our current implementation of shmem is with mmap()ing of files.
+// These files need to be deleted explicitly.
+// In practice this call is only needed for unit tests.
+bool SharedMemory::Delete(const std::string& name) {
+  FilePath path;
+  if (!FilePathForMemoryName(name, &path))
+    return false;
+
+  if (PathExists(path))
+    return base::DeleteFile(path, false);
+
+  // Doesn't exist, so success.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  FilePath path;
+  if (!FilePathForMemoryName(name, &path))
+    return false;
+
+  read_only_ = read_only;
+
+  const char* mode = read_only ? "r" : "r+";
+  ScopedFILE fp(base::OpenFile(path, mode));
+  ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+  if (!readonly_fd.is_valid()) {
+    DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+    return false;
+  }
+  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, offset);
+
+  bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
+  if (mmap_succeeded) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+                      (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  munmap(memory_, mapped_size_);
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return SharedMemoryHandle(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+  if (mapped_file_ > 0) {
+    if (close(mapped_file_) < 0)
+      PLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+  if (readonly_mapped_file_ > 0) {
+    if (close(readonly_mapped_file_) < 0)
+      PLOG(ERROR) << "close";
+    readonly_mapped_file_ = -1;
+  }
+}
+
+bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
+  DCHECK_EQ(-1, mapped_file_);
+  DCHECK_EQ(-1, readonly_mapped_file_);
+  if (fp == NULL)
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  struct stat st = {};
+  if (fstat(fileno(fp.get()), &st))
+    NOTREACHED();
+  if (readonly_fd.is_valid()) {
+    struct stat readonly_st = {};
+    if (fstat(readonly_fd.get(), &readonly_st))
+      NOTREACHED();
+    if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
+      LOG(ERROR) << "writable and read-only inodes don't match; bailing";
+      return false;
+    }
+  }
+
+  mapped_file_ = HANDLE_EINTR(dup(fileno(fp.get())));
+  if (mapped_file_ == -1) {
+    if (errno == EMFILE) {
+      LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
+      return false;
+    } else {
+      NOTREACHED() << "Call to dup failed, errno=" << errno;
+    }
+  }
+  readonly_mapped_file_ = readonly_fd.release();
+
+  return true;
+}
+
+// For the given shmem named |mem_name|, return a filename to mmap()
+// (and possibly create).  Modifies |filename|.  Return false on
+// error, or true of we are happy.
+bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
+                                         FilePath* path) {
+  // mem_name will be used for a filename; make sure it doesn't
+  // contain anything which will confuse us.
+  DCHECK_EQ(std::string::npos, mem_name.find('/'));
+  DCHECK_EQ(std::string::npos, mem_name.find('\0'));
+
+  FilePath temp_dir;
+  if (!GetShmemTempDir(false, &temp_dir))
+    return false;
+
+  std::string name_base = std::string(base::mac::BaseBundleID());
+  *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
+  return true;
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  int handle_to_dup = -1;
+  switch (share_mode) {
+    case SHARE_CURRENT_MODE:
+      handle_to_dup = mapped_file_;
+      break;
+    case SHARE_READONLY:
+      // We could imagine re-opening the file from /dev/fd, but that can't make
+      // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
+      CHECK_GE(readonly_mapped_file_, 0);
+      handle_to_dup = readonly_mapped_file_;
+      break;
+  }
+
+  const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
+  if (new_fd < 0) {
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->SetFileHandle(new_fd, true);
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc
index 26dd4a3..1e93cca 100644
--- a/base/memory/shared_memory_nacl.cc
+++ b/base/memory/shared_memory_nacl.cc
@@ -24,15 +24,15 @@
       requested_size_(0) {
 }
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
     : mapped_file_(handle.fd),
       mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0) {
-}
+      requested_size_(0) {}
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
                            ProcessHandle process)
     : mapped_file_(handle.fd),
       mapped_size_(0),
@@ -139,14 +139,6 @@
   }
 }
 
-void SharedMemory::LockDeprecated() {
-  NOTIMPLEMENTED();
-}
-
-void SharedMemory::UnlockDeprecated() {
-  NOTIMPLEMENTED();
-}
-
 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
                                         SharedMemoryHandle *new_handle,
                                         bool close_self,
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 35d746e..7bd9ecf 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -4,16 +4,13 @@
 
 #include "base/memory/shared_memory.h"
 
-#include <errno.h>
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/safe_strerror.h"
@@ -21,13 +18,6 @@
 #include "base/profiler/scoped_tracker.h"
 #include "base/scoped_generic.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_restrictions.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac/foundation_util.h"
-#endif  // OS_MACOSX
 
 #if defined(OS_ANDROID)
 #include "base/os_compat_android.h"
@@ -38,8 +28,6 @@
 
 namespace {
 
-LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
-
 struct ScopedPathUnlinkerTraits {
   static FilePath* InvalidValue() { return nullptr; }
 
@@ -118,16 +106,16 @@
       requested_size_(0) {
 }
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
     : mapped_file_(handle.fd),
       readonly_mapped_file_(-1),
       mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0) {
-}
+      requested_size_(0) {}
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
                            ProcessHandle process)
     : mapped_file_(handle.fd),
       readonly_mapped_file_(-1),
@@ -298,7 +286,6 @@
     requested_size_ = options.size;
   }
   if (fp == NULL) {
-#if !defined(OS_MACOSX)
     PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
     FilePath dir = path.DirName();
     if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
@@ -308,9 +295,6 @@
                    << "/dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.";
       }
     }
-#else
-    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
-#endif
     return false;
   }
 
@@ -414,16 +398,6 @@
   }
 }
 
-void SharedMemory::LockDeprecated() {
-  g_thread_lock_.Get().Acquire();
-  LockOrUnlockCommon(F_LOCK);
-}
-
-void SharedMemory::UnlockDeprecated() {
-  LockOrUnlockCommon(F_ULOCK);
-  g_thread_lock_.Get().Release();
-}
-
 #if !defined(OS_ANDROID)
 bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
   DCHECK_EQ(-1, mapped_file_);
@@ -477,39 +451,16 @@
   if (!GetShmemTempDir(false, &temp_dir))
     return false;
 
-#if !defined(OS_MACOSX)
 #if defined(GOOGLE_CHROME_BUILD)
   std::string name_base = std::string("com.google.Chrome");
 #else
   std::string name_base = std::string("org.chromium.Chromium");
 #endif
-#else  // OS_MACOSX
-  std::string name_base = std::string(base::mac::BaseBundleID());
-#endif  // OS_MACOSX
   *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
   return true;
 }
 #endif  // !defined(OS_ANDROID)
 
-void SharedMemory::LockOrUnlockCommon(int function) {
-  DCHECK_GE(mapped_file_, 0);
-  while (lockf(mapped_file_, function, 0) < 0) {
-    if (errno == EINTR) {
-      continue;
-    } else if (errno == ENOLCK) {
-      // temporary kernel resource exaustion
-      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
-      continue;
-    } else {
-      NOTREACHED() << "lockf() failed."
-                   << " function:" << function
-                   << " fd:" << mapped_file_
-                   << " errno:" << errno
-                   << " msg:" << base::safe_strerror(errno);
-    }
-  }
-}
-
 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
                                         SharedMemoryHandle* new_handle,
                                         bool close_self,
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
index 6fe5706..c129e18 100644
--- a/base/memory/shared_memory_unittest.cc
+++ b/base/memory/shared_memory_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/atomicops.h"
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
@@ -33,7 +34,7 @@
 #endif
 
 static const int kNumThreads = 5;
-#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
 static const int kNumTasks = 5;
 #endif
 
@@ -90,56 +91,6 @@
 const char* const MultipleThreadMain::s_test_name_ =
     "SharedMemoryOpenThreadTest";
 
-// TODO(port):
-// This test requires the ability to pass file descriptors between processes.
-// We haven't done that yet in Chrome for POSIX.
-#if defined(OS_WIN)
-// Each thread will open the shared memory.  Each thread will take the memory,
-// and keep changing it while trying to lock it, with some small pauses in
-// between. Verify that each thread's value in the shared memory is always
-// correct.
-class MultipleLockThread : public PlatformThread::Delegate {
- public:
-  explicit MultipleLockThread(int id) : id_(id) {}
-  ~MultipleLockThread() override {}
-
-  // PlatformThread::Delegate interface.
-  void ThreadMain() override {
-    const uint32 kDataSize = sizeof(int);
-    SharedMemoryHandle handle = NULL;
-    {
-      SharedMemory memory1;
-      EXPECT_TRUE(memory1.CreateNamedDeprecated(
-          "SharedMemoryMultipleLockThreadTest", true, kDataSize));
-      EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
-      // TODO(paulg): Implement this once we have a posix version of
-      // SharedMemory::ShareToProcess.
-      EXPECT_TRUE(true);
-    }
-
-    SharedMemory memory2(handle, false);
-    EXPECT_TRUE(memory2.Map(kDataSize));
-    volatile int* const ptr = static_cast<int*>(memory2.memory());
-
-    for (int idx = 0; idx < 20; idx++) {
-      memory2.LockDeprecated();
-      int i = (id_ << 16) + idx;
-      *ptr = i;
-      PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
-      EXPECT_EQ(*ptr, i);
-      memory2.UnlockDeprecated();
-    }
-
-    memory2.Close();
-  }
-
- private:
-  int id_;
-
-  DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
-};
-#endif
-
 }  // namespace
 
 // Android doesn't support SharedMemory::Open/Delete/
@@ -320,34 +271,6 @@
   MultipleThreadMain::CleanUp();
 }
 
-// TODO(port): this test requires the MultipleLockThread class
-// (defined above), which requires the ability to pass file
-// descriptors between processes.  We haven't done that yet in Chrome
-// for POSIX.
-#if defined(OS_WIN)
-// Create a set of threads to each open a shared memory segment and write to it
-// with the lock held. Verify that they are always reading/writing consistent
-// data.
-TEST(SharedMemoryTest, Lock) {
-  PlatformThreadHandle thread_handles[kNumThreads];
-  MultipleLockThread* thread_delegates[kNumThreads];
-
-  // Spawn the threads.
-  for (int index = 0; index < kNumThreads; ++index) {
-    PlatformThreadHandle pth;
-    thread_delegates[index] = new MultipleLockThread(index);
-    EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
-    thread_handles[index] = pth;
-  }
-
-  // Wait for the threads to finish.
-  for (int index = 0; index < kNumThreads; ++index) {
-    PlatformThread::Join(thread_handles[index]);
-    delete thread_delegates[index];
-  }
-}
-#endif
-
 // Allocate private (unique) shared memory with an empty string for a
 // name.  Make sure several of them don't point to the same thing as
 // we might expect if the names are equal.
@@ -437,12 +360,13 @@
   // http://crbug.com/320865
   (void)handle;
 #elif defined(OS_POSIX)
-  EXPECT_EQ(O_RDONLY, fcntl(handle.fd, F_GETFL) & O_ACCMODE)
+  int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle);
+  EXPECT_EQ(O_RDONLY, fcntl(handle_fd, F_GETFL) & O_ACCMODE)
       << "The descriptor itself should be read-only.";
 
   errno = 0;
-  void* writable = mmap(
-      NULL, contents.size(), PROT_READ | PROT_WRITE, MAP_SHARED, handle.fd, 0);
+  void* writable = mmap(NULL, contents.size(), PROT_READ | PROT_WRITE,
+                        MAP_SHARED, handle_fd, 0);
   int mmap_errno = errno;
   EXPECT_EQ(MAP_FAILED, writable)
       << "It shouldn't be possible to re-mmap the descriptor writable.";
@@ -596,7 +520,8 @@
 
   EXPECT_TRUE(shared_memory.Create(options));
 
-  int shm_fd = shared_memory.handle().fd;
+  int shm_fd =
+      SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
   struct stat shm_stat;
   EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
   // Neither the group, nor others should be able to read the shared memory
@@ -622,7 +547,8 @@
   // Clean-up the backing file name immediately, we don't need it.
   EXPECT_TRUE(shared_memory.Delete(shared_mem_name));
 
-  int shm_fd = shared_memory.handle().fd;
+  int shm_fd =
+      SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
   struct stat shm_stat;
   EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
   // Neither the group, nor others should have been able to open the shared
@@ -647,7 +573,9 @@
   shared_memory.Close();
 }
 
-#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+// iOS does not allow multiple processes.
+// Android ashmem doesn't support named shared memory.
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
 
 // On POSIX it is especially important we test shmem across processes,
 // not just across threads.  But the test is enabled on all platforms.
@@ -664,53 +592,61 @@
 #if defined(OS_MACOSX)
     mac::ScopedNSAutoreleasePool pool;
 #endif
-    const uint32 kDataSize = 1024;
     SharedMemory memory;
-    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
     EXPECT_TRUE(rv);
     if (rv != true)
       errors++;
-    rv = memory.Map(kDataSize);
+    rv = memory.Map(s_data_size_);
     EXPECT_TRUE(rv);
     if (rv != true)
       errors++;
     int *ptr = static_cast<int*>(memory.memory());
 
-    for (int idx = 0; idx < 20; idx++) {
-      memory.LockDeprecated();
-      int i = (1 << 16) + idx;
-      *ptr = i;
-      PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
-      if (*ptr != i)
-        errors++;
-      memory.UnlockDeprecated();
-    }
-
+    // This runs concurrently in multiple processes. Writes need to be atomic.
+    base::subtle::Barrier_AtomicIncrement(ptr, 1);
     memory.Close();
     return errors;
   }
 
- private:
   static const char* const s_test_name_;
+  static const uint32 s_data_size_;
 };
 
 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
+const uint32 SharedMemoryProcessTest::s_data_size_ = 1024;
 
-TEST_F(SharedMemoryProcessTest, Tasks) {
+TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) {
   SharedMemoryProcessTest::CleanUp();
 
+  // Create a shared memory region. Set the first word to 0.
+  SharedMemory memory;
+  bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
+  ASSERT_TRUE(rv);
+  rv = memory.Map(s_data_size_);
+  ASSERT_TRUE(rv);
+  int* ptr = static_cast<int*>(memory.memory());
+  *ptr = 0;
+
+  // Start |kNumTasks| processes, each of which atomically increments the first
+  // word by 1.
   Process processes[kNumTasks];
   for (int index = 0; index < kNumTasks; ++index) {
     processes[index] = SpawnChild("SharedMemoryTestMain");
     ASSERT_TRUE(processes[index].IsValid());
   }
 
+  // Check that each process exited correctly.
   int exit_code = 0;
   for (int index = 0; index < kNumTasks; ++index) {
     EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
     EXPECT_EQ(0, exit_code);
   }
 
+  // Check that the shared memory region reflects |kNumTasks| increments.
+  ASSERT_EQ(kNumTasks, *ptr);
+
+  memory.Close();
   SharedMemoryProcessTest::CleanUp();
 }
 
@@ -718,6 +654,6 @@
   return SharedMemoryProcessTest::TaskTestMain();
 }
 
-#endif  // !OS_IOS
+#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
 
 }  // namespace base
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
index eacf0d6..40dcaae 100644
--- a/base/memory/shared_memory_win.cc
+++ b/base/memory/shared_memory_win.cc
@@ -29,40 +29,34 @@
 
 SharedMemory::SharedMemory()
     : mapped_file_(NULL),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(false),
-      mapped_size_(0),
-      requested_size_(0),
-      lock_(NULL) {
-}
+      requested_size_(0) {}
 
 SharedMemory::SharedMemory(const std::wstring& name)
-    : mapped_file_(NULL),
+    : name_(name),
+      mapped_file_(NULL),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(false),
-      requested_size_(0),
-      mapped_size_(0),
-      lock_(NULL),
-      name_(name) {
-}
+      requested_size_(0) {}
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
     : mapped_file_(handle),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0),
-      mapped_size_(0),
-      lock_(NULL) {
-}
+      requested_size_(0) {}
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
                            ProcessHandle process)
     : mapped_file_(NULL),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0),
-      mapped_size_(0),
-      lock_(NULL) {
+      requested_size_(0) {
   ::DuplicateHandle(process, handle,
                     GetCurrentProcess(), &mapped_file_,
                     read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
@@ -73,8 +67,6 @@
 SharedMemory::~SharedMemory() {
   Unmap();
   Close();
-  if (lock_ != NULL)
-    CloseHandle(lock_);
 }
 
 // static
@@ -270,26 +262,6 @@
   }
 }
 
-void SharedMemory::LockDeprecated() {
-  if (lock_ == NULL) {
-    std::wstring name = name_;
-    name.append(L"lock");
-    lock_ = CreateMutex(NULL, FALSE, name.c_str());
-    if (lock_ == NULL) {
-      DPLOG(ERROR) << "Could not create mutex.";
-      NOTREACHED();
-      return;  // There is nothing good we can do here.
-    }
-  }
-  DWORD result = WaitForSingleObject(lock_, INFINITE);
-  DCHECK_EQ(result, WAIT_OBJECT_0);
-}
-
-void SharedMemory::UnlockDeprecated() {
-  DCHECK(lock_ != NULL);
-  ReleaseMutex(lock_);
-}
-
 SharedMemoryHandle SharedMemory::handle() const {
   return mapped_file_;
 }
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 4222c77..6bd6730 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -19,6 +19,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_local.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "base/tracked_objects.h"
 
 #if defined(OS_MACOSX)
@@ -170,7 +171,8 @@
   // Tell the incoming queue that we are dying.
   incoming_task_queue_->WillDestroyCurrentMessageLoop();
   incoming_task_queue_ = NULL;
-  message_loop_proxy_ = NULL;
+  unbound_task_runner_ = NULL;
+  task_runner_ = NULL;
 
   // OK, now make it so that no one can find us.
   lazy_tls_ptr.Pointer()->Set(NULL);
@@ -257,27 +259,27 @@
 void MessageLoop::PostTask(
     const tracked_objects::Location& from_here,
     const Closure& task) {
-  message_loop_proxy_->PostTask(from_here, task);
+  task_runner_->PostTask(from_here, task);
 }
 
 void MessageLoop::PostDelayedTask(
     const tracked_objects::Location& from_here,
     const Closure& task,
     TimeDelta delay) {
-  message_loop_proxy_->PostDelayedTask(from_here, task, delay);
+  task_runner_->PostDelayedTask(from_here, task, delay);
 }
 
 void MessageLoop::PostNonNestableTask(
     const tracked_objects::Location& from_here,
     const Closure& task) {
-  message_loop_proxy_->PostNonNestableTask(from_here, task);
+  task_runner_->PostNonNestableTask(from_here, task);
 }
 
 void MessageLoop::PostNonNestableDelayedTask(
     const tracked_objects::Location& from_here,
     const Closure& task,
     TimeDelta delay) {
-  message_loop_proxy_->PostNonNestableDelayedTask(from_here, task, delay);
+  task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
 }
 
 void MessageLoop::Run() {
@@ -367,6 +369,7 @@
 
 //------------------------------------------------------------------------------
 
+// static
 scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
     Type type, MessagePumpFactoryCallback pump_factory) {
   return make_scoped_ptr(new MessageLoop(type, pump_factory));
@@ -386,8 +389,9 @@
       message_histogram_(NULL),
       run_loop_(NULL),
       incoming_task_queue_(new internal::IncomingTaskQueue(this)),
-      message_loop_proxy_(
-          new internal::MessageLoopProxyImpl(incoming_task_queue_)) {
+      unbound_task_runner_(
+          new internal::MessageLoopTaskRunner(incoming_task_queue_)),
+      task_runner_(unbound_task_runner_) {
   // If type is TYPE_CUSTOM non-null pump_factory must be given.
   DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
 }
@@ -403,9 +407,26 @@
   lazy_tls_ptr.Pointer()->Set(this);
 
   incoming_task_queue_->StartScheduling();
-  message_loop_proxy_->BindToCurrentThread();
-  thread_task_runner_handle_.reset(
-      new ThreadTaskRunnerHandle(message_loop_proxy_));
+  unbound_task_runner_->BindToCurrentThread();
+  unbound_task_runner_ = nullptr;
+  SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetTaskRunner(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  DCHECK_EQ(this, current());
+  DCHECK(task_runner->BelongsToCurrentThread());
+  DCHECK(!unbound_task_runner_);
+  task_runner_ = task_runner.Pass();
+  SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetThreadTaskRunnerHandle() {
+  DCHECK_EQ(this, current());
+  // Clear the previous thread task runner first because only one can exist at
+  // a time.
+  thread_task_runner_handle_.reset();
+  thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_));
 }
 
 void MessageLoop::RunHandler() {
@@ -453,10 +474,11 @@
 
   HistogramEvent(kTaskRunEvent);
 
+  TRACE_TASK_EXECUTION("toplevel", pending_task);
+
   FOR_EACH_OBSERVER(TaskObserver, task_observers_,
                     WillProcessTask(pending_task));
-  task_annotator_.RunTask(
-      "MessageLoop::PostTask", "MessageLoop::RunTask", pending_task);
+  task_annotator_.RunTask("MessageLoop::PostTask", pending_task);
   FOR_EACH_OBSERVER(TaskObserver, task_observers_,
                     DidProcessTask(pending_task));
 
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index f2f89d0..fbb8309 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -16,8 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/incoming_task_queue.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/message_loop/message_loop_proxy_impl.h"
+#include "base/message_loop/message_loop_task_runner.h"
 #include "base/message_loop/message_pump.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/observer_list.h"
@@ -296,19 +295,17 @@
   }
   const std::string& thread_name() const { return thread_name_; }
 
-  // Gets the message loop proxy associated with this message loop.
-  //
-  // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces
-  scoped_refptr<MessageLoopProxy> message_loop_proxy() {
-    return message_loop_proxy_;
+  // Gets the TaskRunner associated with this message loop.
+  const scoped_refptr<SingleThreadTaskRunner>& task_runner() {
+    return task_runner_;
   }
 
-  // Gets the TaskRunner associated with this message loop.
-  // TODO(skyostil): Change this to return a const reference to a refptr
-  // once the internal type matches what is being returned (crbug.com/465354).
-  scoped_refptr<SingleThreadTaskRunner> task_runner() {
-    return message_loop_proxy_;
-  }
+  // Sets a new TaskRunner for this message loop. The message loop must already
+  // have been bound to a thread prior to this call, and the task runner must
+  // belong to that thread. Note that changing the task runner will also affect
+  // the ThreadTaskRunnerHandle for the target thread. Must be called on the
+  // thread to which the message loop is bound.
+  void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
 
   // Enables or disables the recursive task processing. This happens in the case
   // of recursive message loops. Some unwanted message loop may occurs when
@@ -425,7 +422,7 @@
   // thread the message loop runs on, before calling Run().
   // Before BindToCurrentThread() is called only Post*Task() functions can
   // be called on the message loop.
-  scoped_ptr<MessageLoop> CreateUnbound(
+  static scoped_ptr<MessageLoop> CreateUnbound(
       Type type,
       MessagePumpFactoryCallback pump_factory);
 
@@ -436,6 +433,10 @@
   // Configure various members and bind this message loop to the current thread.
   void BindToCurrentThread();
 
+  // Sets the ThreadTaskRunnerHandle for the current thread to point to the
+  // task runner for this message loop.
+  void SetThreadTaskRunnerHandle();
+
   // Invokes the actual run loop using the message pump.
   void RunHandler();
 
@@ -531,8 +532,11 @@
 
   scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
 
-  // The message loop proxy associated with this message loop.
-  scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_;
+  // A task runner which we haven't bound to a thread yet.
+  scoped_refptr<internal::MessageLoopTaskRunner> unbound_task_runner_;
+
+  // The task runner associated with this message loop.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
   scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
 
   template <class T, class R> friend class base::subtle::DeleteHelperInternal;
diff --git a/base/message_loop/message_loop_proxy.cc b/base/message_loop/message_loop_proxy.cc
deleted file mode 100644
index e5f0142..0000000
--- a/base/message_loop/message_loop_proxy.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/message_loop/message_loop_proxy.h"
-
-#include "base/bind.h"
-
-namespace base {
-
-MessageLoopProxy::MessageLoopProxy() {
-}
-
-MessageLoopProxy::~MessageLoopProxy() {
-}
-
-}  // namespace base
diff --git a/base/message_loop/message_loop_proxy.h b/base/message_loop/message_loop_proxy.h
deleted file mode 100644
index d5ecc04..0000000
--- a/base/message_loop/message_loop_proxy.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
-#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
-
-#include "base/base_export.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-
-// MessageLoopProxy is deprecated. Code should prefer to depend on TaskRunner
-// (or the various specializations) for passing task runners around, and should
-// use ThreadTaskRunnerHandle::Get() to get the thread's associated task runner.
-//
-// See http://crbug.com/391045 for more details.
-// Example for these changes:
-//
-// base::MessageLoopProxy::current() -> base::ThreadTaskRunnerHandle::Get()
-// scoped_refptr<base::MessageLoopProxy> ->
-//     scoped_refptr<base::SingleThreadTaskRunner>
-// base::MessageLoopProxy -> base::SingleThreadTaskRunner
-
-namespace base {
-
-// This class provides a thread-safe refcounted interface to the Post* methods
-// of a message loop. This class can outlive the target message loop.
-// MessageLoopProxy objects are constructed automatically for all MessageLoops.
-// So, to access them, you can use any of the following:
-//   Thread::message_loop_proxy()
-//   MessageLoop::current()->message_loop_proxy()
-//   MessageLoopProxy::current()
-//
-// TODO(akalin): Now that we have the *TaskRunner interfaces, we can
-// merge this with MessageLoopProxyImpl.
-class BASE_EXPORT MessageLoopProxy : public SingleThreadTaskRunner {
- public:
-  // Gets the MessageLoopProxy for the current message loop, creating one if
-  // needed.
-  static scoped_refptr<MessageLoopProxy> current();
-
- protected:
-  MessageLoopProxy();
-  ~MessageLoopProxy() override;
-};
-
-}  // namespace base
-
-#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
diff --git a/base/message_loop/message_loop_proxy_impl_unittest.cc b/base/message_loop/message_loop_proxy_impl_unittest.cc
deleted file mode 100644
index fa25371..0000000
--- a/base/message_loop/message_loop_proxy_impl_unittest.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/message_loop/message_loop_proxy_impl.h"
-
-#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/threading/thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace base {
-
-class MessageLoopProxyImplTest : public testing::Test {
- public:
-  void Release() const {
-    AssertOnIOThread();
-    Quit();
-  }
-
-  void Quit() const {
-    loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
-  }
-
-  void AssertOnIOThread() const {
-    ASSERT_TRUE(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
-    ASSERT_EQ(io_thread_->message_loop_proxy(),
-              MessageLoopProxy::current());
-  }
-
-  void AssertOnFileThread() const {
-    ASSERT_TRUE(file_thread_->message_loop_proxy()->BelongsToCurrentThread());
-    ASSERT_EQ(file_thread_->message_loop_proxy(),
-              MessageLoopProxy::current());
-  }
-
- protected:
-  void SetUp() override {
-    io_thread_.reset(new Thread("MessageLoopProxyImplTest_IO"));
-    file_thread_.reset(new Thread("MessageLoopProxyImplTest_File"));
-    io_thread_->Start();
-    file_thread_->Start();
-  }
-
-  void TearDown() override {
-    io_thread_->Stop();
-    file_thread_->Stop();
-  }
-
-  static void BasicFunction(MessageLoopProxyImplTest* test) {
-    test->AssertOnFileThread();
-    test->Quit();
-  }
-
-  static void AssertNotRun() {
-    FAIL() << "Callback Should not get executed.";
-  }
-
-  class DeletedOnFile {
-   public:
-    explicit DeletedOnFile(MessageLoopProxyImplTest* test) : test_(test) {}
-
-    ~DeletedOnFile() {
-      test_->AssertOnFileThread();
-      test_->Quit();
-    }
-
-   private:
-    MessageLoopProxyImplTest* test_;
-  };
-
-  scoped_ptr<Thread> io_thread_;
-  scoped_ptr<Thread> file_thread_;
-
- private:
-  mutable MessageLoop loop_;
-};
-
-TEST_F(MessageLoopProxyImplTest, Release) {
-  EXPECT_TRUE(io_thread_->message_loop_proxy()->ReleaseSoon(FROM_HERE, this));
-  MessageLoop::current()->Run();
-}
-
-TEST_F(MessageLoopProxyImplTest, Delete) {
-  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
-  EXPECT_TRUE(file_thread_->message_loop_proxy()->DeleteSoon(
-      FROM_HERE, deleted_on_file));
-  MessageLoop::current()->Run();
-}
-
-TEST_F(MessageLoopProxyImplTest, PostTask) {
-  EXPECT_TRUE(file_thread_->message_loop_proxy()->PostTask(
-      FROM_HERE, Bind(&MessageLoopProxyImplTest::BasicFunction,
-                            Unretained(this))));
-  MessageLoop::current()->Run();
-}
-
-TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadExits) {
-  scoped_ptr<Thread> test_thread(
-      new Thread("MessageLoopProxyImplTest_Dummy"));
-  test_thread->Start();
-  scoped_refptr<MessageLoopProxy> message_loop_proxy =
-      test_thread->message_loop_proxy();
-  test_thread->Stop();
-
-  bool ret = message_loop_proxy->PostTask(
-      FROM_HERE,
-      Bind(&MessageLoopProxyImplTest::AssertNotRun));
-  EXPECT_FALSE(ret);
-}
-
-TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadIsDeleted) {
-  scoped_refptr<MessageLoopProxy> message_loop_proxy;
-  {
-    scoped_ptr<Thread> test_thread(
-        new Thread("MessageLoopProxyImplTest_Dummy"));
-    test_thread->Start();
-    message_loop_proxy = test_thread->message_loop_proxy();
-  }
-  bool ret = message_loop_proxy->PostTask(
-      FROM_HERE,
-      Bind(&MessageLoopProxyImplTest::AssertNotRun));
-  EXPECT_FALSE(ret);
-}
-
-}  // namespace base
diff --git a/base/message_loop/message_loop_proxy_unittest.cc b/base/message_loop/message_loop_proxy_unittest.cc
deleted file mode 100644
index 0b0d9f8..0000000
--- a/base/message_loop/message_loop_proxy_unittest.cc
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/message_loop/message_loop_proxy.h"
-
-#include "base/atomic_sequence_num.h"
-#include "base/bind.h"
-#include "base/debug/leak_annotations.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-
-namespace {
-
-class MessageLoopProxyTest : public testing::Test {
- public:
-  MessageLoopProxyTest()
-      : current_loop_(new MessageLoop()),
-        task_thread_("task_thread"),
-        thread_sync_(true, false) {
-  }
-
-  void DeleteCurrentMessageLoop() {
-    current_loop_.reset();
-  }
-
- protected:
-  void SetUp() override {
-    // Use SetUp() instead of the constructor to avoid posting a task to a
-    // partialy constructed object.
-    task_thread_.Start();
-
-    // Allow us to pause the |task_thread_|'s MessageLoop.
-    task_thread_.message_loop()->PostTask(
-        FROM_HERE,
-        Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
-  }
-
-  void TearDown() override {
-    // Make sure the |task_thread_| is not blocked, and stop the thread
-    // fully before destuction because its tasks may still depend on the
-    // |thread_sync_| event.
-    thread_sync_.Signal();
-    task_thread_.Stop();
-    DeleteCurrentMessageLoop();
-  }
-
-  // Make LoopRecorder threadsafe so that there is defined behavior even if a
-  // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
-  class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
-   public:
-    LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
-                 int* destruct_order)
-        : run_on_(run_on),
-          deleted_on_(deleted_on),
-          destruct_order_(destruct_order) {
-    }
-
-    void RecordRun() {
-      *run_on_ = MessageLoop::current();
-    }
-
-   private:
-    friend class RefCountedThreadSafe<LoopRecorder>;
-    ~LoopRecorder() {
-      *deleted_on_ = MessageLoop::current();
-      *destruct_order_ = g_order.GetNext();
-    }
-
-    MessageLoop** run_on_;
-    MessageLoop** deleted_on_;
-    int* destruct_order_;
-  };
-
-  static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
-    recorder->RecordRun();
-  }
-
-  static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
-    recorder->RecordRun();
-    MessageLoop::current()->QuitWhenIdle();
-  }
-
-  void UnblockTaskThread() {
-    thread_sync_.Signal();
-  }
-
-  void BlockTaskThreadHelper() {
-    thread_sync_.Wait();
-  }
-
-  static StaticAtomicSequenceNumber g_order;
-
-  scoped_ptr<MessageLoop> current_loop_;
-  Thread task_thread_;
-
- private:
-  base::WaitableEvent thread_sync_;
-};
-
-StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
-
-TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
-  MessageLoop* task_run_on = NULL;
-  MessageLoop* task_deleted_on = NULL;
-  int task_delete_order = -1;
-  MessageLoop* reply_run_on = NULL;
-  MessageLoop* reply_deleted_on = NULL;
-  int reply_delete_order = -1;
-
-  scoped_refptr<LoopRecorder> task_recoder =
-      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
-  scoped_refptr<LoopRecorder> reply_recoder =
-      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
-
-  ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
-      FROM_HERE,
-      Bind(&RecordLoop, task_recoder),
-      Bind(&RecordLoopAndQuit, reply_recoder)));
-
-  // Die if base::Bind doesn't retain a reference to the recorders.
-  task_recoder = NULL;
-  reply_recoder = NULL;
-  ASSERT_FALSE(task_deleted_on);
-  ASSERT_FALSE(reply_deleted_on);
-
-  UnblockTaskThread();
-  current_loop_->Run();
-
-  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
-  EXPECT_EQ(current_loop_.get(), task_deleted_on);
-  EXPECT_EQ(current_loop_.get(), reply_run_on);
-  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
-  EXPECT_LT(task_delete_order, reply_delete_order);
-}
-
-TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
-  MessageLoop* task_run_on = NULL;
-  MessageLoop* task_deleted_on = NULL;
-  int task_delete_order = -1;
-  MessageLoop* reply_run_on = NULL;
-  MessageLoop* reply_deleted_on = NULL;
-  int reply_delete_order = -1;
-
-  scoped_refptr<LoopRecorder> task_recoder =
-      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
-  scoped_refptr<LoopRecorder> reply_recoder =
-      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
-
-  // Grab a MessageLoopProxy to a dead MessageLoop.
-  scoped_refptr<MessageLoopProxy> task_loop_proxy =
-      task_thread_.message_loop_proxy();
-  UnblockTaskThread();
-  task_thread_.Stop();
-
-  ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
-      FROM_HERE,
-      Bind(&RecordLoop, task_recoder),
-      Bind(&RecordLoopAndQuit, reply_recoder)));
-
-  // The relay should have properly deleted its resources leaving us as the only
-  // reference.
-  EXPECT_EQ(task_delete_order, reply_delete_order);
-  ASSERT_TRUE(task_recoder->HasOneRef());
-  ASSERT_TRUE(reply_recoder->HasOneRef());
-
-  // Nothing should have run though.
-  EXPECT_FALSE(task_run_on);
-  EXPECT_FALSE(reply_run_on);
-}
-
-TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
-  MessageLoop* task_run_on = NULL;
-  MessageLoop* task_deleted_on = NULL;
-  int task_delete_order = -1;
-  MessageLoop* reply_run_on = NULL;
-  MessageLoop* reply_deleted_on = NULL;
-  int reply_delete_order = -1;
-
-  scoped_refptr<LoopRecorder> task_recoder =
-      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
-  scoped_refptr<LoopRecorder> reply_recoder =
-      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
-
-  // Enqueue the relay.
-  ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
-      FROM_HERE,
-      Bind(&RecordLoop, task_recoder),
-      Bind(&RecordLoopAndQuit, reply_recoder)));
-
-  // Die if base::Bind doesn't retain a reference to the recorders.
-  task_recoder = NULL;
-  reply_recoder = NULL;
-  ASSERT_FALSE(task_deleted_on);
-  ASSERT_FALSE(reply_deleted_on);
-
-  current_loop_->Run();
-
-  EXPECT_EQ(current_loop_.get(), task_run_on);
-  EXPECT_EQ(current_loop_.get(), task_deleted_on);
-  EXPECT_EQ(current_loop_.get(), reply_run_on);
-  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
-  EXPECT_LT(task_delete_order, reply_delete_order);
-}
-
-TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
-  // Annotate the scope as having memory leaks to suppress heapchecker reports.
-  ANNOTATE_SCOPED_MEMORY_LEAK;
-  MessageLoop* task_run_on = NULL;
-  MessageLoop* task_deleted_on = NULL;
-  int task_delete_order = -1;
-  MessageLoop* reply_run_on = NULL;
-  MessageLoop* reply_deleted_on = NULL;
-  int reply_delete_order = -1;
-
-  scoped_refptr<LoopRecorder> task_recoder =
-      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
-  scoped_refptr<LoopRecorder> reply_recoder =
-      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
-
-  // Enqueue the relay.
-  task_thread_.message_loop_proxy()->PostTaskAndReply(
-      FROM_HERE,
-      Bind(&RecordLoop, task_recoder),
-      Bind(&RecordLoopAndQuit, reply_recoder));
-
-  // Die if base::Bind doesn't retain a reference to the recorders.
-  task_recoder = NULL;
-  reply_recoder = NULL;
-  ASSERT_FALSE(task_deleted_on);
-  ASSERT_FALSE(reply_deleted_on);
-
-  UnblockTaskThread();
-
-  // Mercilessly whack the current loop before |reply| gets to run.
-  current_loop_.reset();
-
-  // This should ensure the relay has been run.  We need to record the
-  // MessageLoop pointer before stopping the thread because Thread::Stop() will
-  // NULL out its own pointer.
-  MessageLoop* task_loop = task_thread_.message_loop();
-  task_thread_.Stop();
-
-  EXPECT_EQ(task_loop, task_run_on);
-  ASSERT_FALSE(task_deleted_on);
-  EXPECT_FALSE(reply_run_on);
-  ASSERT_FALSE(reply_deleted_on);
-  EXPECT_EQ(task_delete_order, reply_delete_order);
-
-  // The PostTaskAndReplyRelay is leaked here.  Even if we had a reference to
-  // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
-  // checks that MessageLoop::current() is the the same as when the
-  // PostTaskAndReplyRelay object was constructed.  However, this loop must have
-  // aleady been deleted in order to perform this test.  See
-  // http://crbug.com/86301.
-}
-
-}  // namespace
-
-}  // namespace base
diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_task_runner.cc
similarity index 62%
rename from base/message_loop/message_loop_proxy_impl.cc
rename to base/message_loop/message_loop_task_runner.cc
index 580620d..d553cfe 100644
--- a/base/message_loop/message_loop_proxy_impl.cc
+++ b/base/message_loop/message_loop_task_runner.cc
@@ -2,29 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop/message_loop_proxy_impl.h"
+#include "base/message_loop/message_loop_task_runner.h"
 
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/message_loop/incoming_task_queue.h"
-#include "base/message_loop/message_loop.h"
 
 namespace base {
 namespace internal {
 
-MessageLoopProxyImpl::MessageLoopProxyImpl(
+MessageLoopTaskRunner::MessageLoopTaskRunner(
     scoped_refptr<IncomingTaskQueue> incoming_queue)
-    : incoming_queue_(incoming_queue),
-      valid_thread_id_(kInvalidThreadId) {
-}
+    : incoming_queue_(incoming_queue), valid_thread_id_(kInvalidThreadId) {}
 
-void MessageLoopProxyImpl::BindToCurrentThread() {
+void MessageLoopTaskRunner::BindToCurrentThread() {
   AutoLock lock(valid_thread_id_lock_);
   DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
   valid_thread_id_ = PlatformThread::CurrentId();
 }
 
-bool MessageLoopProxyImpl::PostDelayedTask(
+bool MessageLoopTaskRunner::PostDelayedTask(
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
@@ -32,7 +29,7 @@
   return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true);
 }
 
-bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
+bool MessageLoopTaskRunner::PostNonNestableDelayedTask(
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
@@ -40,22 +37,13 @@
   return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false);
 }
 
-bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const {
+bool MessageLoopTaskRunner::RunsTasksOnCurrentThread() const {
   AutoLock lock(valid_thread_id_lock_);
   return valid_thread_id_ == PlatformThread::CurrentId();
 }
 
-MessageLoopProxyImpl::~MessageLoopProxyImpl() {
-}
+MessageLoopTaskRunner::~MessageLoopTaskRunner() {}
 
 }  // namespace internal
 
-scoped_refptr<MessageLoopProxy>
-MessageLoopProxy::current() {
-  MessageLoop* cur_loop = MessageLoop::current();
-  if (!cur_loop)
-    return NULL;
-  return cur_loop->message_loop_proxy();
-}
-
 }  // namespace base
diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_task_runner.h
similarity index 60%
rename from base/message_loop/message_loop_proxy_impl.h
rename to base/message_loop/message_loop_task_runner.h
index fa611c2..dc2947d 100644
--- a/base/message_loop/message_loop_proxy_impl.h
+++ b/base/message_loop/message_loop_task_runner.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
-#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
 
 #include "base/base_export.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/pending_task.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 
@@ -17,18 +17,18 @@
 
 class IncomingTaskQueue;
 
-// A stock implementation of MessageLoopProxy that is created and managed by a
-// MessageLoop. For now a MessageLoopProxyImpl can only be created as part of a
-// MessageLoop.
-class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {
+// A stock implementation of SingleThreadTaskRunner that is created and managed
+// by a MessageLoop. For now a MessageLoopTaskRunner can only be created as
+// part of a MessageLoop.
+class BASE_EXPORT MessageLoopTaskRunner : public SingleThreadTaskRunner {
  public:
-  explicit MessageLoopProxyImpl(
+  explicit MessageLoopTaskRunner(
       scoped_refptr<IncomingTaskQueue> incoming_queue);
 
-  // Initialize this message loop proxy on the current thread.
+  // Initialize this message loop task runner on the current thread.
   void BindToCurrentThread();
 
-  // MessageLoopProxy implementation
+  // SingleThreadTaskRunner implementation
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
                        base::TimeDelta delay) override;
@@ -38,10 +38,10 @@
   bool RunsTasksOnCurrentThread() const override;
 
  private:
-  friend class RefCountedThreadSafe<MessageLoopProxyImpl>;
-  ~MessageLoopProxyImpl() override;
+  friend class RefCountedThreadSafe<MessageLoopTaskRunner>;
+  ~MessageLoopTaskRunner() override;
 
-  // THe incoming queue receiving all posted tasks.
+  // The incoming queue receiving all posted tasks.
   scoped_refptr<IncomingTaskQueue> incoming_queue_;
 
   // ID of the thread |this| was created on.  Could be accessed on multiple
@@ -49,10 +49,10 @@
   PlatformThreadId valid_thread_id_;
   mutable Lock valid_thread_id_lock_;
 
-  DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopTaskRunner);
 };
 
 }  // namespace internal
 }  // namespace base
 
-#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
diff --git a/base/message_loop/message_loop_task_runner_unittest.cc b/base/message_loop/message_loop_task_runner_unittest.cc
new file mode 100644
index 0000000..caf88af
--- /dev/null
+++ b/base/message_loop/message_loop_task_runner_unittest.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_task_runner.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class MessageLoopTaskRunnerTest : public testing::Test {
+ public:
+  MessageLoopTaskRunnerTest()
+      : current_loop_(new MessageLoop()),
+        task_thread_("task_thread"),
+        thread_sync_(true, false) {}
+
+  void DeleteCurrentMessageLoop() { current_loop_.reset(); }
+
+ protected:
+  void SetUp() override {
+    // Use SetUp() instead of the constructor to avoid posting a task to a
+    // partialy constructed object.
+    task_thread_.Start();
+
+    // Allow us to pause the |task_thread_|'s MessageLoop.
+    task_thread_.message_loop()->PostTask(
+        FROM_HERE, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper,
+                        Unretained(this)));
+  }
+
+  void TearDown() override {
+    // Make sure the |task_thread_| is not blocked, and stop the thread
+    // fully before destuction because its tasks may still depend on the
+    // |thread_sync_| event.
+    thread_sync_.Signal();
+    task_thread_.Stop();
+    DeleteCurrentMessageLoop();
+  }
+
+  // Make LoopRecorder threadsafe so that there is defined behavior even if a
+  // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
+  class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
+   public:
+    LoopRecorder(MessageLoop** run_on,
+                 MessageLoop** deleted_on,
+                 int* destruct_order)
+        : run_on_(run_on),
+          deleted_on_(deleted_on),
+          destruct_order_(destruct_order) {}
+
+    void RecordRun() { *run_on_ = MessageLoop::current(); }
+
+   private:
+    friend class RefCountedThreadSafe<LoopRecorder>;
+    ~LoopRecorder() {
+      *deleted_on_ = MessageLoop::current();
+      *destruct_order_ = g_order.GetNext();
+    }
+
+    MessageLoop** run_on_;
+    MessageLoop** deleted_on_;
+    int* destruct_order_;
+  };
+
+  static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+  }
+
+  static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void UnblockTaskThread() { thread_sync_.Signal(); }
+
+  void BlockTaskThreadHelper() { thread_sync_.Wait(); }
+
+  static StaticAtomicSequenceNumber g_order;
+
+  scoped_ptr<MessageLoop> current_loop_;
+  Thread task_thread_;
+
+ private:
+  base::WaitableEvent thread_sync_;
+};
+
+StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  ASSERT_TRUE(task_thread_.task_runner()->PostTaskAndReply(
+      FROM_HERE, Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+  current_loop_->Run();
+
+  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Grab a task runner to a dead MessageLoop.
+  scoped_refptr<SingleThreadTaskRunner> task_runner =
+      task_thread_.task_runner();
+  UnblockTaskThread();
+  task_thread_.Stop();
+
+  ASSERT_FALSE(
+      task_runner->PostTaskAndReply(FROM_HERE, Bind(&RecordLoop, task_recoder),
+                                    Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // The relay should have properly deleted its resources leaving us as the only
+  // reference.
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+  ASSERT_TRUE(task_recoder->HasOneRef());
+  ASSERT_TRUE(reply_recoder->HasOneRef());
+
+  // Nothing should have run though.
+  EXPECT_FALSE(task_run_on);
+  EXPECT_FALSE(reply_run_on);
+}
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_SameLoop) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  ASSERT_TRUE(current_loop_->task_runner()->PostTaskAndReply(
+      FROM_HERE, Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  current_loop_->Run();
+
+  EXPECT_EQ(current_loop_.get(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
+  // Annotate the scope as having memory leaks to suppress heapchecker reports.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  task_thread_.task_runner()->PostTaskAndReply(
+      FROM_HERE, Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+
+  // Mercilessly whack the current loop before |reply| gets to run.
+  current_loop_.reset();
+
+  // This should ensure the relay has been run.  We need to record the
+  // MessageLoop pointer before stopping the thread because Thread::Stop() will
+  // NULL out its own pointer.
+  MessageLoop* task_loop = task_thread_.message_loop();
+  task_thread_.Stop();
+
+  EXPECT_EQ(task_loop, task_run_on);
+  ASSERT_FALSE(task_deleted_on);
+  EXPECT_FALSE(reply_run_on);
+  ASSERT_FALSE(reply_deleted_on);
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+
+  // The PostTaskAndReplyRelay is leaked here.  Even if we had a reference to
+  // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
+  // checks that MessageLoop::current() is the the same as when the
+  // PostTaskAndReplyRelay object was constructed.  However, this loop must have
+  // aleady been deleted in order to perform this test.  See
+  // http://crbug.com/86301.
+}
+
+class MessageLoopTaskRunnerThreadingTest : public testing::Test {
+ public:
+  void Release() const {
+    AssertOnIOThread();
+    Quit();
+  }
+
+  void Quit() const {
+    loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void AssertOnIOThread() const {
+    ASSERT_TRUE(io_thread_->task_runner()->BelongsToCurrentThread());
+    ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+  }
+
+  void AssertOnFileThread() const {
+    ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread());
+    ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+  }
+
+ protected:
+  void SetUp() override {
+    io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
+    file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
+    io_thread_->Start();
+    file_thread_->Start();
+  }
+
+  void TearDown() override {
+    io_thread_->Stop();
+    file_thread_->Stop();
+  }
+
+  static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) {
+    test->AssertOnFileThread();
+    test->Quit();
+  }
+
+  static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
+
+  class DeletedOnFile {
+   public:
+    explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test)
+        : test_(test) {}
+
+    ~DeletedOnFile() {
+      test_->AssertOnFileThread();
+      test_->Quit();
+    }
+
+   private:
+    MessageLoopTaskRunnerThreadingTest* test_;
+  };
+
+  scoped_ptr<Thread> io_thread_;
+  scoped_ptr<Thread> file_thread_;
+
+ private:
+  mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Release) {
+  EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) {
+  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+  EXPECT_TRUE(
+      file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) {
+  EXPECT_TRUE(file_thread_->task_runner()->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction,
+                      Unretained(this))));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) {
+  scoped_ptr<Thread> test_thread(
+      new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+  test_thread->Start();
+  scoped_refptr<SingleThreadTaskRunner> task_runner =
+      test_thread->task_runner();
+  test_thread->Stop();
+
+  bool ret = task_runner->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) {
+  scoped_refptr<SingleThreadTaskRunner> task_runner;
+  {
+    scoped_ptr<Thread> test_thread(
+        new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+    test_thread->Start();
+    task_runner = test_thread->task_runner();
+  }
+  bool ret = task_runner->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index ddde6bb..9c17017 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -10,12 +10,12 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy_impl.h"
 #include "base/message_loop/message_loop_test.h"
 #include "base/pending_task.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/test_simple_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
@@ -1012,4 +1012,26 @@
 }
 #endif  // defined(OS_WIN)
 
+TEST(MessageLoopTest, SetTaskRunner) {
+  MessageLoop loop;
+  scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+
+  loop.SetTaskRunner(new_runner);
+  EXPECT_EQ(new_runner, loop.task_runner());
+  EXPECT_EQ(new_runner, ThreadTaskRunnerHandle::Get());
+}
+
+TEST(MessageLoopTest, OriginalRunnerWorks) {
+  MessageLoop loop;
+  scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+  scoped_refptr<SingleThreadTaskRunner> original_runner(loop.task_runner());
+  loop.SetTaskRunner(new_runner);
+
+  scoped_refptr<Foo> foo(new Foo());
+  original_runner->PostTask(FROM_HERE,
+                            Bind(&Foo::Test1ConstRef, foo.get(), "a"));
+  loop.RunUntilIdle();
+  EXPECT_EQ(1, foo->test_count());
+}
+
 }  // namespace base
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
index 914977b..53e3363 100644
--- a/base/message_loop/message_pump_mac.mm
+++ b/base/message_loop/message_pump_mac.mm
@@ -10,6 +10,7 @@
 #include <limits>
 
 #include "base/logging.h"
+#include "base/mac/call_with_eh_frame.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/run_loop.h"
@@ -300,7 +301,9 @@
 // static
 void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
-  self->RunWork();
+  base::mac::CallWithEHFrame(^{
+    self->RunWork();
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::RunWorkSource.
@@ -359,7 +362,9 @@
 // static
 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
-  self->RunIdleWork();
+  base::mac::CallWithEHFrame(^{
+    self->RunIdleWork();
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
@@ -393,7 +398,9 @@
 // static
 void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
-  self->RunNestingDeferredWork();
+  base::mac::CallWithEHFrame(^{
+    self->RunNestingDeferredWork();
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
@@ -440,15 +447,16 @@
                                                CFRunLoopActivity activity,
                                                void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  base::mac::CallWithEHFrame(^{
+    // Attempt to do some idle work before going to sleep.
+    self->RunIdleWork();
 
-  // Attempt to do some idle work before going to sleep.
-  self->RunIdleWork();
-
-  // The run loop is about to go to sleep.  If any of the work done since it
-  // started or woke up resulted in a nested run loop running,
-  // nesting-deferred work may have accumulated.  Schedule it for processing
-  // if appropriate.
-  self->MaybeScheduleNestingDeferredWork();
+    // The run loop is about to go to sleep.  If any of the work done since it
+    // started or woke up resulted in a nested run loop running,
+    // nesting-deferred work may have accumulated.  Schedule it for processing
+    // if appropriate.
+    self->MaybeScheduleNestingDeferredWork();
+  });
 }
 
 // Called from the run loop.
@@ -463,7 +471,9 @@
   // level did not sleep or exit, nesting-deferred work may have accumulated
   // if a nested loop ran.  Schedule nesting-deferred work for processing if
   // appropriate.
-  self->MaybeScheduleNestingDeferredWork();
+  base::mac::CallWithEHFrame(^{
+    self->MaybeScheduleNestingDeferredWork();
+  });
 }
 
 // Called from the run loop.
@@ -498,7 +508,9 @@
       // to sleep or exiting.  It must be called before decrementing the
       // value so that the value still corresponds to the level of the exiting
       // loop.
-      self->MaybeScheduleNestingDeferredWork();
+      base::mac::CallWithEHFrame(^{
+        self->MaybeScheduleNestingDeferredWork();
+      });
       --self->nesting_level_;
       break;
 
@@ -506,7 +518,9 @@
       break;
   }
 
-  self->EnterExitRunLoop(activity);
+  base::mac::CallWithEHFrame(^{
+    self->EnterExitRunLoop(activity);
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop.  The default
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index f1a1042..ed84d86 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -1021,9 +1021,9 @@
     scoped_refptr<base::FieldTrial> trial(
         new base::FieldTrial("test", kBucketCount, "default", entropy));
     for (int j = 0; j < kBucketCount; ++j)
-      trial->AppendGroup(base::StringPrintf("%d", j), 1);
+      trial->AppendGroup(base::IntToString(j), 1);
 
-    EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name());
+    EXPECT_EQ(base::IntToString(i), trial->group_name());
   }
 }
 
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 1550420..0c9fcb7 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -17,6 +17,7 @@
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/sample_vector.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/pickle.h"
@@ -130,6 +131,23 @@
                     flags);
 }
 
+HistogramBase* Histogram::FactoryGet(const char* name,
+                                     Sample minimum,
+                                     Sample maximum,
+                                     size_t bucket_count,
+                                     int32 flags) {
+  return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const char* name,
+                                         TimeDelta minimum,
+                                         TimeDelta maximum,
+                                         size_t bucket_count,
+                                         int32 flags) {
+  return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
+                        flags);
+}
+
 // Calculate what range of values are held in each bucket.
 // We have to be careful that we don't pick a ratio between starting points in
 // consecutive buckets that is sooo small, that the integer bounds are the same
@@ -262,6 +280,8 @@
   if (value < 0)
     value = 0;
   samples_->Accumulate(value, 1);
+
+  FindAndRunCallback(value);
 }
 
 scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
@@ -531,6 +551,23 @@
                     flags);
 }
 
+HistogramBase* LinearHistogram::FactoryGet(const char* name,
+                                           Sample minimum,
+                                           Sample maximum,
+                                           size_t bucket_count,
+                                           int32 flags) {
+  return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
+                                               TimeDelta minimum,
+                                               TimeDelta maximum,
+                                               size_t bucket_count,
+                                               int32 flags) {
+  return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
+                        flags);
+}
+
 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
       const std::string& name,
       Sample minimum,
@@ -676,6 +713,10 @@
   return histogram;
 }
 
+HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) {
+  return FactoryGet(std::string(name), flags);
+}
+
 HistogramType BooleanHistogram::GetHistogramType() const {
   return BOOLEAN_HISTOGRAM;
 }
@@ -736,6 +777,13 @@
   return histogram;
 }
 
+HistogramBase* CustomHistogram::FactoryGet(
+    const char* name,
+    const std::vector<Sample>& custom_ranges,
+    int32 flags) {
+  return FactoryGet(std::string(name), custom_ranges, flags);
+}
+
 HistogramType CustomHistogram::GetHistogramType() const {
   return CUSTOM_HISTOGRAM;
 }
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index c13f05e..58bc029 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -121,6 +121,20 @@
                                        size_t bucket_count,
                                        int32 flags);
 
+  // Overloads of the above two functions that take a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const char* name,
+                                       base::TimeDelta minimum,
+                                       base::TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
   static void InitializeBucketRanges(Sample minimum,
                                      Sample maximum,
                                      BucketRanges* ranges);
@@ -277,6 +291,20 @@
                                        size_t bucket_count,
                                        int32 flags);
 
+  // Overloads of the above two functions that take a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const char* name,
+                                       TimeDelta minimum,
+                                       TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
   struct DescriptionPair {
     Sample sample;
     const char* description;  // Null means end of a list of pairs.
@@ -339,6 +367,11 @@
  public:
   static HistogramBase* FactoryGet(const std::string& name, int32 flags);
 
+  // Overload of the above function that takes a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name, int32 flags);
+
   HistogramType GetHistogramType() const override;
 
  private:
@@ -364,6 +397,13 @@
                                    const std::vector<Sample>& custom_ranges,
                                    int32 flags);
 
+  // Overload of the above function that takes a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   const std::vector<Sample>& custom_ranges,
+                                   int32 flags);
+
   // Overridden from Histogram:
   HistogramType GetHistogramType() const override;
 
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index de34c79..6b3f69c 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/pickle.h"
 #include "base/process/process_handle.h"
 #include "base/strings/stringprintf.h"
@@ -117,6 +118,16 @@
   serializer.Serialize(root);
 }
 
+void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
+  if ((flags_ & kCallbackExists) == 0)
+    return;
+
+  StatisticsRecorder::OnSampleCallback cb =
+      StatisticsRecorder::FindCallback(histogram_name());
+  if (!cb.is_null())
+    cb.Run(sample);
+}
+
 void HistogramBase::WriteAsciiBucketGraph(double current_size,
                                           double max_size,
                                           std::string* output) const {
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index 006395b..1bc1f6e 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -31,7 +31,7 @@
 // processes into the browser. If you create another class that inherits from
 // HistogramBase, add new histogram types and names below.
 
-enum BASE_EXPORT HistogramType {
+enum HistogramType {
   HISTOGRAM,
   LINEAR_HISTOGRAM,
   BOOLEAN_HISTOGRAM,
@@ -74,6 +74,12 @@
     // the source histogram!).
     kIPCSerializationSourceFlag = 0x10,
 
+    // Indicates that a callback exists for when a new sample is recorded on
+    // this histogram. We store this as a flag with the histogram since
+    // histograms can be in performance critical code, and this allows us
+    // to shortcut looking up the callback if it doesn't exist.
+    kCallbackExists = 0x20,
+
     // Only for Histogram and its sub classes: fancy bucket-naming support.
     kHexRangePrintingFlag = 0x8000,
   };
@@ -92,7 +98,7 @@
   explicit HistogramBase(const std::string& name);
   virtual ~HistogramBase();
 
-  std::string histogram_name() const { return histogram_name_; }
+  const std::string& histogram_name() const { return histogram_name_; }
 
   // Comapres |name| to the histogram name and triggers a DCHECK if they do not
   // match. This is a helper function used by histogram macros, which results in
@@ -172,6 +178,10 @@
                              double scaled_sum,
                              std::string* output) const;
 
+  // Retrieves the callback for this histogram, if one exists, and runs it
+  // passing |sample| as the parameter.
+  void FindAndRunCallback(Sample sample) const;
+
  private:
   const std::string histogram_name_;
   int32_t flags_;
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
index 2aee1a5..9867df8 100644
--- a/base/metrics/histogram_macros.h
+++ b/base/metrics/histogram_macros.h
@@ -189,6 +189,9 @@
 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
     name, sample, 1, 100, 50)
 
+#define UMA_HISTOGRAM_COUNTS_1000(name, sample) \
+  UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 1000, 50)
+
 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
     name, sample, 1, 10000, 50)
 
diff --git a/base/metrics/histogram_snapshot_manager_unittest.cc b/base/metrics/histogram_snapshot_manager_unittest.cc
index 3a1fd40..e9e7398 100644
--- a/base/metrics/histogram_snapshot_manager_unittest.cc
+++ b/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -7,8 +7,8 @@
 #include <string>
 #include <vector>
 
-#include "base/metrics/histogram.h"
 #include "base/metrics/histogram_delta_serialization.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/statistics_recorder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index 2e3a1ee..f189267 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/sample_vector.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/pickle.h"
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
index e5cdb43..a853dce 100644
--- a/base/metrics/sparse_histogram.cc
+++ b/base/metrics/sparse_histogram.cc
@@ -46,8 +46,12 @@
 }
 
 void SparseHistogram::Add(Sample value) {
-  base::AutoLock auto_lock(lock_);
-  samples_.Accumulate(value, 1);
+  {
+    base::AutoLock auto_lock(lock_);
+    samples_.Accumulate(value, 1);
+  }
+
+  FindAndRunCallback(value);
 }
 
 scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 85408e1..87ffa3d 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
 #include "base/values.h"
@@ -57,10 +58,19 @@
       histogram_to_return = histogram;
     } else {
       const std::string& name = histogram->histogram_name();
-      HistogramMap::iterator it = histograms_->find(name);
+      HistogramMap::iterator it = histograms_->find(HistogramNameRef(name));
       if (histograms_->end() == it) {
-        (*histograms_)[name] = histogram;
+        (*histograms_)[HistogramNameRef(name)] = histogram;
         ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+        // If there are callbacks for this histogram, we set the kCallbackExists
+        // flag.
+        auto callback_iterator = callbacks_->find(name);
+        if (callback_iterator != callbacks_->end()) {
+          if (!callback_iterator->second.is_null())
+            histogram->SetFlags(HistogramBase::kCallbackExists);
+          else
+            histogram->ClearFlags(HistogramBase::kCallbackExists);
+        }
         histogram_to_return = histogram;
       } else if (histogram == it->second) {
         // The histogram was registered before.
@@ -190,7 +200,7 @@
     return;
 
   for (const auto& entry : *histograms_) {
-    DCHECK_EQ(entry.first, entry.second->histogram_name());
+    DCHECK_EQ(entry.first.name_, entry.second->histogram_name());
     output->push_back(entry.second);
   }
 }
@@ -219,12 +229,64 @@
   if (histograms_ == NULL)
     return NULL;
 
-  HistogramMap::iterator it = histograms_->find(name);
+  HistogramMap::iterator it = histograms_->find(HistogramNameRef(name));
   if (histograms_->end() == it)
     return NULL;
   return it->second;
 }
 
+// static
+bool StatisticsRecorder::SetCallback(
+    const std::string& name,
+    const StatisticsRecorder::OnSampleCallback& cb) {
+  DCHECK(!cb.is_null());
+  if (lock_ == NULL)
+    return false;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return false;
+
+  if (ContainsKey(*callbacks_, name))
+    return false;
+  callbacks_->insert(std::make_pair(name, cb));
+
+  auto histogram_iterator = histograms_->find(HistogramNameRef(name));
+  if (histogram_iterator != histograms_->end())
+    histogram_iterator->second->SetFlags(HistogramBase::kCallbackExists);
+
+  return true;
+}
+
+// static
+void StatisticsRecorder::ClearCallback(const std::string& name) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  callbacks_->erase(name);
+
+  // We also clear the flag from the histogram (if it exists).
+  auto histogram_iterator = histograms_->find(HistogramNameRef(name));
+  if (histogram_iterator != histograms_->end())
+    histogram_iterator->second->ClearFlags(HistogramBase::kCallbackExists);
+}
+
+// static
+StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
+    const std::string& name) {
+  if (lock_ == NULL)
+    return OnSampleCallback();
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return OnSampleCallback();
+
+  auto callback_iterator = callbacks_->find(name);
+  return callback_iterator != callbacks_->end() ? callback_iterator->second
+                                                : OnSampleCallback();
+}
+
 // private static
 void StatisticsRecorder::GetSnapshot(const std::string& query,
                                      Histograms* snapshot) {
@@ -235,7 +297,7 @@
     return;
 
   for (const auto& entry : *histograms_) {
-    if (entry.first.find(query) != std::string::npos)
+    if (entry.first.name_.find(query) != std::string::npos)
       snapshot->push_back(entry.second);
   }
 }
@@ -256,6 +318,7 @@
   }
   base::AutoLock auto_lock(*lock_);
   histograms_ = new HistogramMap;
+  callbacks_ = new CallbackMap;
   ranges_ = new RangesMap;
 
   if (VLOG_IS_ON(1))
@@ -274,14 +337,17 @@
 
   // Clean up.
   scoped_ptr<HistogramMap> histograms_deleter;
+  scoped_ptr<CallbackMap> callbacks_deleter;
   scoped_ptr<RangesMap> ranges_deleter;
   // We don't delete lock_ on purpose to avoid having to properly protect
   // against it going away after we checked for NULL in the static methods.
   {
     base::AutoLock auto_lock(*lock_);
     histograms_deleter.reset(histograms_);
+    callbacks_deleter.reset(callbacks_);
     ranges_deleter.reset(ranges_);
     histograms_ = NULL;
+    callbacks_ = NULL;
     ranges_ = NULL;
   }
   // We are going to leak the histograms and the ranges.
@@ -291,6 +357,8 @@
 // static
 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
 // static
+StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL;
+// static
 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
 // static
 base::Lock* StatisticsRecorder::lock_ = NULL;
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index b523057..729f230 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -17,13 +17,14 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/lazy_instance.h"
+#include "base/metrics/histogram_base.h"
 
 namespace base {
 
 class BucketRanges;
-class HistogramBase;
 class Lock;
 
 class BASE_EXPORT StatisticsRecorder {
@@ -75,9 +76,47 @@
   // histograms).
   static void GetSnapshot(const std::string& query, Histograms* snapshot);
 
+  typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
+
+  // SetCallback sets the callback to notify when a new sample is recorded on
+  // the histogram referred to by |histogram_name|. The call to this method can
+  // be be done before or after the histogram is created. This method is thread
+  // safe. The return value is whether or not the callback was successfully set.
+  static bool SetCallback(const std::string& histogram_name,
+                          const OnSampleCallback& callback);
+
+  // ClearCallback clears any callback set on the histogram referred to by
+  // |histogram_name|. This method is thread safe.
+  static void ClearCallback(const std::string& histogram_name);
+
+  // FindCallback retrieves the callback for the histogram referred to by
+  // |histogram_name|, or a null callback if no callback exists for this
+  // histogram. This method is thread safe.
+  static OnSampleCallback FindCallback(const std::string& histogram_name);
+
  private:
+  // HistogramNameRef holds a weak const ref to the name field of the associated
+  // Histogram object, allowing re-use of the underlying string storage for the
+  // map keys. The wrapper is required as using "const std::string&" as the key
+  // results in compile errors.
+  struct HistogramNameRef {
+    explicit HistogramNameRef(const std::string& name) : name_(name){};
+
+    // Operator < is necessary to use this type as a std::map key.
+    bool operator<(const HistogramNameRef& other) const {
+      return name_ < other.name_;
+    }
+
+    // Weak, owned by the associated Histogram object.
+    const std::string& name_;
+  };
+
   // We keep all registered histograms in a map, from name to histogram.
-  typedef std::map<std::string, HistogramBase*> HistogramMap;
+  typedef std::map<HistogramNameRef, HistogramBase*> HistogramMap;
+
+  // We keep a map of callbacks to histograms, so that as histograms are
+  // created, we can set the callback properly.
+  typedef std::map<std::string, OnSampleCallback> CallbackMap;
 
   // We keep all |bucket_ranges_| in a map, from checksum to a list of
   // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
@@ -103,6 +142,7 @@
   static void DumpHistogramsToVlog(void* instance);
 
   static HistogramMap* histograms_;
+  static CallbackMap* callbacks_;
   static RangesMap* ranges_;
 
   // Lock protects access to above maps.
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index d26df69..b18c580 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -4,9 +4,11 @@
 
 #include <vector>
 
+#include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -312,4 +314,178 @@
   EXPECT_TRUE(json.empty());
 }
 
+namespace {
+
+// CallbackCheckWrapper is simply a convenient way to check and store that
+// a callback was actually run.
+struct CallbackCheckWrapper {
+  CallbackCheckWrapper() : called(false), last_histogram_value(0) {}
+
+  void OnHistogramChanged(base::HistogramBase::Sample histogram_value) {
+    called = true;
+    last_histogram_value = histogram_value;
+  }
+
+  bool called;
+  base::HistogramBase::Sample last_histogram_value;
+};
+
+}  // namespace
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+
+  result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_FALSE(result);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_FALSE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  histogram->Add(1);
+
+  EXPECT_TRUE(callback_wrapper.called);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  base::StatisticsRecorder::ClearCallback("TestHistogram");
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0);
+
+  histogram->Add(1);
+
+  EXPECT_FALSE(callback_wrapper.called);
+}
+
+// Check that callback is used.
+TEST_F(StatisticsRecorderTest, CallbackUsedTest) {
+  {
+    HistogramBase* histogram = Histogram::FactoryGet(
+        "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+    EXPECT_TRUE(histogram);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                    base::Unretained(&callback_wrapper)));
+
+    histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+        "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestLinearHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    linear_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    std::vector<int> custom_ranges;
+    custom_ranges.push_back(1);
+    custom_ranges.push_back(5);
+    HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+        "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestCustomHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    custom_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
+        "TestSparseHistogram", HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestSparseHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    custom_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+}
+
+// Check that setting a callback before the histogram exists works.
+TEST_F(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
+  CallbackCheckWrapper callback_wrapper;
+
+  base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+  histogram->Add(1);
+
+  EXPECT_TRUE(callback_wrapper.called);
+  EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+}
+
 }  // namespace base
diff --git a/base/pickle.cc b/base/pickle.cc
index 09d42c9..cf4a865 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -317,13 +317,17 @@
 }
 
 void Pickle::Resize(size_t new_capacity) {
-  new_capacity = AlignInt(new_capacity, kPayloadUnit);
-
   CHECK_NE(capacity_after_header_, kCapacityReadOnly);
-  void* p = realloc(header_, header_size_ + new_capacity);
+  capacity_after_header_ = AlignInt(new_capacity, kPayloadUnit);
+  void* p = realloc(header_, GetTotalAllocatedSize());
   CHECK(p);
   header_ = reinterpret_cast<Header*>(p);
-  capacity_after_header_ = new_capacity;
+}
+
+size_t Pickle::GetTotalAllocatedSize() const {
+  if (capacity_after_header_ == kCapacityReadOnly)
+    return 0;
+  return header_size_ + capacity_after_header_;
 }
 
 // static
diff --git a/base/pickle.h b/base/pickle.h
index 7a6b0c8..c9fef71 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -153,12 +153,18 @@
   // Performs a deep copy.
   Pickle& operator=(const Pickle& other);
 
-  // Returns the size of the Pickle's data.
+  // Returns the number of bytes written in the Pickle, including the header.
   size_t size() const { return header_size_ + header_->payload_size; }
 
   // Returns the data for this Pickle.
   const void* data() const { return header_; }
 
+  // Returns the effective memory capacity of this Pickle, that is, the total
+  // number of bytes currently dynamically allocated or 0 in the case of a
+  // read-only Pickle. This should be used only for diagnostic / profiling
+  // purposes.
+  size_t GetTotalAllocatedSize() const;
+
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
diff --git a/base/port.h b/base/port.h
deleted file mode 100644
index 56c4d4e..0000000
--- a/base/port.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2006-2008 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_PORT_H_
-#define BASE_PORT_H_
-
-#include <stdarg.h>
-#include "build/build_config.h"
-
-// DEPRECATED: Use ...LL and ...ULL suffixes.
-// TODO(viettrungluu): Delete these. These are only here until |GG_(U)INT64_C|
-// are deleted (some other header files (re)define |GG_(U)INT64_C|, so our
-// definitions of them must exactly match theirs).
-#ifdef COMPILER_MSVC
-#define GG_LONGLONG(x) x##I64
-#define GG_ULONGLONG(x) x##UI64
-#else
-#define GG_LONGLONG(x) x##LL
-#define GG_ULONGLONG(x) x##ULL
-#endif
-
-// DEPRECATED: In Chromium, we force-define __STDC_CONSTANT_MACROS, so you can
-// just use the regular (U)INTn_C macros from <stdint.h>.
-// TODO(viettrungluu): Remove the remaining GG_(U)INTn_C macros.
-#define GG_INT64_C(x)   GG_LONGLONG(x)
-#define GG_UINT64_C(x)  GG_ULONGLONG(x)
-
-// Define an OS-neutral wrapper for shared library entry points
-#if defined(OS_WIN)
-#define API_CALL __stdcall
-#else
-#define API_CALL
-#endif
-
-#endif  // BASE_PORT_H_
diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc
index 92abba1..efb4a75 100644
--- a/base/prefs/default_pref_store.cc
+++ b/base/prefs/default_pref_store.cc
@@ -29,7 +29,7 @@
 void DefaultPrefStore::SetDefaultValue(const std::string& key,
                                        scoped_ptr<Value> value) {
   DCHECK(!GetValue(key, NULL));
-  prefs_.SetValue(key, value.release());
+  prefs_.SetValue(key, value.Pass());
 }
 
 void DefaultPrefStore::ReplaceDefaultValue(const std::string& key,
@@ -37,7 +37,7 @@
   const Value* old_value = NULL;
   GetValue(key, &old_value);
   bool notify = !old_value->Equals(value.get());
-  prefs_.SetValue(key, value.release());
+  prefs_.SetValue(key, value.Pass());
   if (notify)
     FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
 }
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
index c2ff425..354fd94 100644
--- a/base/prefs/json_pref_store.cc
+++ b/base/prefs/json_pref_store.cc
@@ -221,31 +221,29 @@
 }
 
 void JsonPrefStore::SetValue(const std::string& key,
-                             base::Value* value,
+                             scoped_ptr<base::Value> value,
                              uint32 flags) {
   DCHECK(CalledOnValidThread());
 
   DCHECK(value);
-  scoped_ptr<base::Value> new_value(value);
   base::Value* old_value = NULL;
   prefs_->Get(key, &old_value);
   if (!old_value || !value->Equals(old_value)) {
-    prefs_->Set(key, new_value.Pass());
+    prefs_->Set(key, value.Pass());
     ReportValueChanged(key, flags);
   }
 }
 
 void JsonPrefStore::SetValueSilently(const std::string& key,
-                                     base::Value* value,
+                                     scoped_ptr<base::Value> value,
                                      uint32 flags) {
   DCHECK(CalledOnValidThread());
 
   DCHECK(value);
-  scoped_ptr<base::Value> new_value(value);
   base::Value* old_value = NULL;
   prefs_->Get(key, &old_value);
   if (!old_value || !value->Equals(old_value)) {
-    prefs_->Set(key, new_value.Pass());
+    prefs_->Set(key, value.Pass());
     ScheduleWrite(flags);
   }
 }
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
index d6943e0..0be7702 100644
--- a/base/prefs/json_pref_store.h
+++ b/base/prefs/json_pref_store.h
@@ -84,10 +84,10 @@
   // PersistentPrefStore overrides:
   bool GetMutableValue(const std::string& key, base::Value** result) override;
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool ReadOnly() const override;
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
index 4c7bc1f..5195a18 100644
--- a/base/prefs/json_pref_store_unittest.cc
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -192,7 +192,8 @@
   EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
   base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
 
-  pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()),
+  pref_store->SetValue(kSomeDirectory,
+                       make_scoped_ptr(new StringValue(some_path.value())),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
   EXPECT_TRUE(actual->GetAsString(&path));
@@ -204,7 +205,8 @@
   EXPECT_TRUE(actual->GetAsBoolean(&boolean));
   EXPECT_TRUE(boolean);
 
-  pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false),
+  pref_store->SetValue(kNewWindowsInTabs,
+                       make_scoped_ptr(new FundamentalValue(false)),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
   EXPECT_TRUE(actual->GetAsBoolean(&boolean));
@@ -214,15 +216,16 @@
   int integer = 0;
   EXPECT_TRUE(actual->GetAsInteger(&integer));
   EXPECT_EQ(20, integer);
-  pref_store->SetValue(kMaxTabs, new FundamentalValue(10),
+  pref_store->SetValue(kMaxTabs, make_scoped_ptr(new FundamentalValue(10)),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
   EXPECT_TRUE(actual->GetAsInteger(&integer));
   EXPECT_EQ(10, integer);
 
-  pref_store->SetValue(kLongIntPref,
-                       new StringValue(base::Int64ToString(214748364842LL)),
-                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  pref_store->SetValue(
+      kLongIntPref,
+      make_scoped_ptr(new StringValue(base::Int64ToString(214748364842LL))),
+      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
   EXPECT_TRUE(actual->GetAsString(&string_value));
   int64 value;
@@ -312,9 +315,9 @@
       pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   // Set some keys with empty values.
-  pref_store->SetValue("list", new base::ListValue,
+  pref_store->SetValue("list", make_scoped_ptr(new base::ListValue),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  pref_store->SetValue("dict", new base::DictionaryValue,
+  pref_store->SetValue("dict", make_scoped_ptr(new base::DictionaryValue),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   // Write to file.
@@ -343,9 +346,9 @@
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
       pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
-  base::DictionaryValue* dict = new base::DictionaryValue;
+  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
   dict->SetString("key", "value");
-  pref_store->SetValue("dict", dict,
+  pref_store->SetValue("dict", dict.Pass(),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   pref_store->RemoveValue("dict.key",
@@ -845,7 +848,8 @@
 
   // Set a normal pref and check that it gets scheduled to be written.
   ASSERT_FALSE(file_writer->HasPendingWrite());
-  pref_store->SetValue("normal", new base::StringValue("normal"),
+  pref_store->SetValue("normal",
+                       make_scoped_ptr(new base::StringValue("normal")),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   ASSERT_TRUE(file_writer->HasPendingWrite());
   file_writer->DoScheduledWrite();
@@ -854,14 +858,15 @@
 
   // Set a lossy pref and check that it is not scheduled to be written.
   // SetValue/RemoveValue.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
   pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
   // SetValueSilently/RemoveValueSilently.
-  pref_store->SetValueSilently("lossy", new base::StringValue("lossy"),
+  pref_store->SetValueSilently("lossy",
+                               make_scoped_ptr(new base::StringValue("lossy")),
                                WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
   pref_store->RemoveValueSilently("lossy",
@@ -869,7 +874,7 @@
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
   // ReportValueChanged.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
   pref_store->ReportValueChanged("lossy",
@@ -890,12 +895,13 @@
 
   // Set a lossy pref and check that it is not scheduled to be written.
   ASSERT_FALSE(file_writer->HasPendingWrite());
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
   // Set a normal pref and check that it is scheduled to be written.
-  pref_store->SetValue("normal", new base::StringValue("normal"),
+  pref_store->SetValue("normal",
+                       make_scoped_ptr(new base::StringValue("normal")),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   ASSERT_TRUE(file_writer->HasPendingWrite());
 
@@ -912,12 +918,13 @@
 
   // Set a normal pref and check that it is scheduled to be written.
   ASSERT_FALSE(file_writer->HasPendingWrite());
-  pref_store->SetValue("normal", new base::StringValue("normal"),
+  pref_store->SetValue("normal",
+                       make_scoped_ptr(new base::StringValue("normal")),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   ASSERT_TRUE(file_writer->HasPendingWrite());
 
   // Set a lossy pref and check that the write is still scheduled.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_TRUE(file_writer->HasPendingWrite());
 
@@ -933,7 +940,7 @@
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
 
   // Set a lossy pref and check that it is not scheduled to be written.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc
index 4c236f1..d76b537 100644
--- a/base/prefs/overlay_user_pref_store.cc
+++ b/base/prefs/overlay_user_pref_store.cc
@@ -58,31 +58,31 @@
     return false;
 
   *result = underlay_value->DeepCopy();
-  overlay_.SetValue(key, *result);
+  overlay_.SetValue(key, make_scoped_ptr(*result));
   return true;
 }
 
 void OverlayUserPrefStore::SetValue(const std::string& key,
-                                    base::Value* value,
+                                    scoped_ptr<base::Value> value,
                                     uint32 flags) {
   if (!ShallBeStoredInOverlay(key)) {
-    underlay_->SetValue(GetUnderlayKey(key), value, flags);
+    underlay_->SetValue(GetUnderlayKey(key), value.Pass(), flags);
     return;
   }
 
-  if (overlay_.SetValue(key, value))
+  if (overlay_.SetValue(key, value.Pass()))
     ReportValueChanged(key, flags);
 }
 
 void OverlayUserPrefStore::SetValueSilently(const std::string& key,
-                                            base::Value* value,
+                                            scoped_ptr<base::Value> value,
                                             uint32 flags) {
   if (!ShallBeStoredInOverlay(key)) {
-    underlay_->SetValueSilently(GetUnderlayKey(key), value, flags);
+    underlay_->SetValueSilently(GetUnderlayKey(key), value.Pass(), flags);
     return;
   }
 
-  overlay_.SetValue(key, value);
+  overlay_.SetValue(key, value.Pass());
 }
 
 void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32 flags) {
diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h
index 885da08..737b426 100644
--- a/base/prefs/overlay_user_pref_store.h
+++ b/base/prefs/overlay_user_pref_store.h
@@ -40,10 +40,10 @@
   // Methods of PersistentPrefStore.
   bool GetMutableValue(const std::string& key, base::Value** result) override;
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool ReadOnly() const override;
diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc
index 06b4ec9..bf5e6a5 100644
--- a/base/prefs/overlay_user_pref_store_unittest.cc
+++ b/base/prefs/overlay_user_pref_store_unittest.cc
@@ -48,22 +48,22 @@
   overlay_->AddObserver(&obs);
 
   // Check that underlay first value is reported.
-  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(42)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(overlay_key);
 
   // Check that underlay overwriting is reported.
-  underlay_->SetValue(overlay_key, new FundamentalValue(43),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(43)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(overlay_key);
 
   // Check that overwriting change in overlay is reported.
-  overlay_->SetValue(overlay_key, new FundamentalValue(44),
+  overlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(44)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(overlay_key);
 
   // Check that hidden underlay change is not reported.
-  underlay_->SetValue(overlay_key, new FundamentalValue(45),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(45)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
@@ -78,16 +78,17 @@
   obs.VerifyAndResetChangedKey(overlay_key);
 
   // Check respecting of silence.
-  overlay_->SetValueSilently(overlay_key, new FundamentalValue(46),
+  overlay_->SetValueSilently(overlay_key,
+                             make_scoped_ptr(new FundamentalValue(46)),
                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
   overlay_->RemoveObserver(&obs);
 
   // Check successful unsubscription.
-  underlay_->SetValue(overlay_key, new FundamentalValue(47),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(47)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  overlay_->SetValue(overlay_key, new FundamentalValue(48),
+  overlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(48)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 }
@@ -97,7 +98,7 @@
   EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
   EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
 
-  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(42)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   // Value shines through:
@@ -107,7 +108,7 @@
   EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
   EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
 
-  overlay_->SetValue(overlay_key, new FundamentalValue(43),
+  overlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(43)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
@@ -129,7 +130,7 @@
 
 // Check that GetMutableValue does not return the dictionary of the underlay.
 TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
-  underlay_->SetValue(overlay_key, new DictionaryValue,
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new DictionaryValue),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   Value* modify = NULL;
@@ -159,12 +160,12 @@
   const Value* value = NULL;
 
   // Check that underlay first value is reported.
-  underlay_->SetValue(regular_key, new FundamentalValue(42),
+  underlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(42)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(regular_key);
 
   // Check that underlay overwriting is reported.
-  underlay_->SetValue(regular_key, new FundamentalValue(43),
+  underlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(43)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(regular_key);
 
@@ -173,7 +174,7 @@
   EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
 
   // Check that overwriting change in overlay is reported.
-  overlay_->SetValue(regular_key, new FundamentalValue(44),
+  overlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(44)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(regular_key);
 
@@ -193,16 +194,17 @@
   EXPECT_FALSE(underlay_->GetValue(regular_key, &value));
 
   // Check respecting of silence.
-  overlay_->SetValueSilently(regular_key, new FundamentalValue(46),
+  overlay_->SetValueSilently(regular_key,
+                             make_scoped_ptr(new FundamentalValue(46)),
                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
   overlay_->RemoveObserver(&obs);
 
   // Check successful unsubscription.
-  underlay_->SetValue(regular_key, new FundamentalValue(47),
+  underlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(47)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  overlay_->SetValue(regular_key, new FundamentalValue(48),
+  overlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(48)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 }
@@ -216,12 +218,14 @@
 
   // Check that if there is no override in the overlay, changing underlay value
   // is reported as changing an overlay value.
-  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(42),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(42)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(mapped_overlay_key);
 
   // Check that underlay overwriting is reported.
-  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(43),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(43)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(mapped_overlay_key);
 
@@ -233,7 +237,8 @@
   EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
 
   // Check that overwriting change in overlay is reported.
-  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44),
+  overlay_->SetValue(mapped_overlay_key,
+                     make_scoped_ptr(new FundamentalValue(44)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(mapped_overlay_key);
 
@@ -247,7 +252,8 @@
   EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
 
   // Check that hidden underlay change is not reported.
-  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(45)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
@@ -266,16 +272,19 @@
   EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value));
 
   // Check respecting of silence.
-  overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46),
+  overlay_->SetValueSilently(mapped_overlay_key,
+                             make_scoped_ptr(new FundamentalValue(46)),
                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
   overlay_->RemoveObserver(&obs);
 
   // Check successful unsubscription.
-  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(47),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(47)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48),
+  overlay_->SetValue(mapped_overlay_key,
+                     make_scoped_ptr(new FundamentalValue(48)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 }
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc
index a9749b2..c53b896 100644
--- a/base/prefs/pref_service.cc
+++ b/base/prefs/pref_service.cc
@@ -471,7 +471,8 @@
     } else {
       NOTREACHED();
     }
-    user_pref_store_->SetValueSilently(path, value, GetWriteFlags(pref));
+    user_pref_store_->SetValueSilently(path, make_scoped_ptr(value),
+                                       GetWriteFlags(pref));
   }
   return value;
 }
@@ -498,7 +499,7 @@
     return;
   }
 
-  user_pref_store_->SetValue(path, owned_value.release(), GetWriteFlags(pref));
+  user_pref_store_->SetValue(path, owned_value.Pass(), GetWriteFlags(pref));
 }
 
 void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
diff --git a/base/prefs/pref_service_unittest.cc b/base/prefs/pref_service_unittest.cc
index 262d7e9..2506b1d 100644
--- a/base/prefs/pref_service_unittest.cc
+++ b/base/prefs/pref_service_unittest.cc
@@ -239,17 +239,15 @@
   }
 
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override {
     SetLastWriteFlags(flags);
-    delete value;
   }
 
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override {
     SetLastWriteFlags(flags);
-    delete value;
   }
 
   void RemoveValue(const std::string& key, uint32 flags) override {
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc
index 5f2dc50..93eadb7 100644
--- a/base/prefs/pref_value_map.cc
+++ b/base/prefs/pref_value_map.cc
@@ -13,60 +13,43 @@
 
 PrefValueMap::PrefValueMap() {}
 
-PrefValueMap::~PrefValueMap() {
-  Clear();
-}
+PrefValueMap::~PrefValueMap() {}
 
 bool PrefValueMap::GetValue(const std::string& key,
                             const base::Value** value) const {
-  const Map::const_iterator entry = prefs_.find(key);
-  if (entry == prefs_.end())
-    return false;
+  const base::Value* got_value = prefs_.get(key);
+  if (value && got_value)
+    *value = got_value;
 
-  if (value)
-    *value = entry->second;
-  return true;
+  return !!got_value;
 }
 
 bool PrefValueMap::GetValue(const std::string& key, base::Value** value) {
-  const Map::const_iterator entry = prefs_.find(key);
-  if (entry == prefs_.end())
-    return false;
+  base::Value* got_value = prefs_.get(key);
+  if (value && got_value)
+    *value = got_value;
 
-  if (value)
-    *value = entry->second;
-  return true;
+  return !!got_value;
 }
 
-bool PrefValueMap::SetValue(const std::string& key, base::Value* value) {
+bool PrefValueMap::SetValue(const std::string& key,
+                            scoped_ptr<base::Value> value) {
   DCHECK(value);
-  auto result = prefs_.insert(std::make_pair(key, value));
-  if (result.second)
-    return true;
 
-  scoped_ptr<base::Value> value_ptr(value);
-  const Map::iterator& entry = result.first;
-  if (base::Value::Equals(entry->second, value))
+  base::Value* old_value = prefs_.get(key);
+  if (old_value && value->Equals(old_value))
     return false;
 
-  delete entry->second;
-  entry->second = value_ptr.release();
-
+  prefs_.set(key, value.Pass());
   return true;
 }
 
 bool PrefValueMap::RemoveValue(const std::string& key) {
-  const Map::iterator entry = prefs_.find(key);
-  if (entry == prefs_.end())
-    return false;
-
-  delete entry->second;
-  prefs_.erase(entry);
-  return true;
+  return prefs_.erase(key) != 0;
 }
 
 void PrefValueMap::Clear() {
-  STLDeleteValues(&prefs_);
+  prefs_.clear();
 }
 
 void PrefValueMap::Swap(PrefValueMap* other) {
@@ -96,7 +79,7 @@
 }
 
 void PrefValueMap::SetBoolean(const std::string& key, bool value) {
-  SetValue(key, new base::FundamentalValue(value));
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)));
 }
 
 bool PrefValueMap::GetString(const std::string& key,
@@ -107,7 +90,7 @@
 
 void PrefValueMap::SetString(const std::string& key,
                              const std::string& value) {
-  SetValue(key, new base::StringValue(value));
+  SetValue(key, make_scoped_ptr(new base::StringValue(value)));
 }
 
 bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
@@ -116,11 +99,11 @@
 }
 
 void PrefValueMap::SetInteger(const std::string& key, const int value) {
-  SetValue(key, new base::FundamentalValue(value));
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)));
 }
 
 void PrefValueMap::SetDouble(const std::string& key, const double value) {
-  SetValue(key, new base::FundamentalValue(value));
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)));
 }
 
 void PrefValueMap::GetDifferingKeys(
diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h
index 12b30c6..7d43f2b 100644
--- a/base/prefs/pref_value_map.h
+++ b/base/prefs/pref_value_map.h
@@ -9,7 +9,8 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/base_prefs_export.h"
 
 namespace base {
@@ -19,7 +20,7 @@
 // A generic string to value map used by the PrefStore implementations.
 class BASE_PREFS_EXPORT PrefValueMap {
  public:
-  using Map = base::hash_map<std::string, base::Value*>;
+  using Map = base::ScopedPtrHashMap<std::string, scoped_ptr<base::Value>>;
   using iterator = Map::iterator;
   using const_iterator = Map::const_iterator;
 
@@ -32,9 +33,9 @@
   bool GetValue(const std::string& key, const base::Value** value) const;
   bool GetValue(const std::string& key, base::Value** value);
 
-  // Sets a new |value| for |key|. Takes ownership of |value|, which must be
-  // non-NULL. Returns true if the value changed.
-  bool SetValue(const std::string& key, base::Value* value);
+  // Sets a new |value| for |key|. |value| must be non-null. Returns true if the
+  // value changed.
+  bool SetValue(const std::string& key, scoped_ptr<base::Value> value);
 
   // Removes the value for |key| from the map. Returns true if a value was
   // removed.
diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc
index 82499da..f78c999 100644
--- a/base/prefs/pref_value_map_unittest.cc
+++ b/base/prefs/pref_value_map_unittest.cc
@@ -16,9 +16,9 @@
   EXPECT_FALSE(map.GetValue("key", &result));
   EXPECT_FALSE(result);
 
-  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
-  EXPECT_FALSE(map.SetValue("key", new StringValue("test")));
-  EXPECT_TRUE(map.SetValue("key", new StringValue("hi mom!")));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_FALSE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("hi mom!"))));
 
   EXPECT_TRUE(map.GetValue("key", &result));
   EXPECT_TRUE(StringValue("hi mom!").Equals(result));
@@ -26,7 +26,7 @@
 
 TEST(PrefValueMapTest, GetAndSetIntegerValue) {
   PrefValueMap map;
-  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5)));
+  ASSERT_TRUE(map.SetValue("key", make_scoped_ptr(new FundamentalValue(5))));
 
   int int_value = 0;
   EXPECT_TRUE(map.GetInteger("key", &int_value));
@@ -39,7 +39,7 @@
 
 TEST(PrefValueMapTest, SetDoubleValue) {
   PrefValueMap map;
-  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5.5)));
+  ASSERT_TRUE(map.SetValue("key", make_scoped_ptr(new FundamentalValue(5.5))));
 
   const Value* result = NULL;
   ASSERT_TRUE(map.GetValue("key", &result));
@@ -52,7 +52,7 @@
   PrefValueMap map;
   EXPECT_FALSE(map.RemoveValue("key"));
 
-  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
   EXPECT_TRUE(map.GetValue("key", NULL));
 
   EXPECT_TRUE(map.RemoveValue("key"));
@@ -63,7 +63,7 @@
 
 TEST(PrefValueMapTest, Clear) {
   PrefValueMap map;
-  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
   EXPECT_TRUE(map.GetValue("key", NULL));
 
   map.Clear();
@@ -73,9 +73,12 @@
 
 TEST(PrefValueMapTest, GetDifferingKeys) {
   PrefValueMap reference;
-  EXPECT_TRUE(reference.SetValue("b", new StringValue("test")));
-  EXPECT_TRUE(reference.SetValue("c", new StringValue("test")));
-  EXPECT_TRUE(reference.SetValue("e", new StringValue("test")));
+  EXPECT_TRUE(
+      reference.SetValue("b", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      reference.SetValue("c", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      reference.SetValue("e", make_scoped_ptr(new StringValue("test"))));
 
   PrefValueMap check;
   std::vector<std::string> differing_paths;
@@ -87,9 +90,9 @@
   expected_differing_paths.push_back("e");
   EXPECT_EQ(expected_differing_paths, differing_paths);
 
-  EXPECT_TRUE(check.SetValue("a", new StringValue("test")));
-  EXPECT_TRUE(check.SetValue("c", new StringValue("test")));
-  EXPECT_TRUE(check.SetValue("d", new StringValue("test")));
+  EXPECT_TRUE(check.SetValue("a", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(check.SetValue("c", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(check.SetValue("d", make_scoped_ptr(new StringValue("test"))));
 
   reference.GetDifferingKeys(&check, &differing_paths);
   expected_differing_paths.clear();
@@ -102,14 +105,20 @@
 
 TEST(PrefValueMapTest, SwapTwoMaps) {
   PrefValueMap first_map;
-  EXPECT_TRUE(first_map.SetValue("a", new StringValue("test")));
-  EXPECT_TRUE(first_map.SetValue("b", new StringValue("test")));
-  EXPECT_TRUE(first_map.SetValue("c", new StringValue("test")));
+  EXPECT_TRUE(
+      first_map.SetValue("a", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      first_map.SetValue("b", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      first_map.SetValue("c", make_scoped_ptr(new StringValue("test"))));
 
   PrefValueMap second_map;
-  EXPECT_TRUE(second_map.SetValue("d", new StringValue("test")));
-  EXPECT_TRUE(second_map.SetValue("e", new StringValue("test")));
-  EXPECT_TRUE(second_map.SetValue("f", new StringValue("test")));
+  EXPECT_TRUE(
+      second_map.SetValue("d", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      second_map.SetValue("e", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      second_map.SetValue("f", make_scoped_ptr(new StringValue("test"))));
 
   first_map.Swap(&second_map);
 
diff --git a/base/prefs/testing_pref_service.h b/base/prefs/testing_pref_service.h
index 7587383..cbc978d 100644
--- a/base/prefs/testing_pref_service.h
+++ b/base/prefs/testing_pref_service.h
@@ -182,7 +182,7 @@
     SetPref(TestingPrefStore* pref_store,
             const std::string& path,
             base::Value* value) {
-  pref_store->SetValue(path, value,
+  pref_store->SetValue(path, make_scoped_ptr(value),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 }
 
diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc
index 1a1e6bc..2322f4e 100644
--- a/base/prefs/testing_pref_store.cc
+++ b/base/prefs/testing_pref_store.cc
@@ -43,18 +43,18 @@
 }
 
 void TestingPrefStore::SetValue(const std::string& key,
-                                base::Value* value,
+                                scoped_ptr<base::Value> value,
                                 uint32 flags) {
-  if (prefs_.SetValue(key, value)) {
+  if (prefs_.SetValue(key, value.Pass())) {
     committed_ = false;
     NotifyPrefValueChanged(key);
   }
 }
 
 void TestingPrefStore::SetValueSilently(const std::string& key,
-                                        base::Value* value,
+                                        scoped_ptr<base::Value> value,
                                         uint32 flags) {
-  if (prefs_.SetValue(key, value))
+  if (prefs_.SetValue(key, value.Pass()))
     committed_ = false;
 }
 
@@ -115,15 +115,18 @@
 
 void TestingPrefStore::SetString(const std::string& key,
                                  const std::string& value) {
-  SetValue(key, new base::StringValue(value), DEFAULT_PREF_WRITE_FLAGS);
+  SetValue(key, make_scoped_ptr(new base::StringValue(value)),
+           DEFAULT_PREF_WRITE_FLAGS);
 }
 
 void TestingPrefStore::SetInteger(const std::string& key, int value) {
-  SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)),
+           DEFAULT_PREF_WRITE_FLAGS);
 }
 
 void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
-  SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)),
+           DEFAULT_PREF_WRITE_FLAGS);
 }
 
 bool TestingPrefStore::GetString(const std::string& key,
diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h
index f43a030..72e61b3 100644
--- a/base/prefs/testing_pref_store.h
+++ b/base/prefs/testing_pref_store.h
@@ -32,10 +32,10 @@
   bool GetMutableValue(const std::string& key, base::Value** result) override;
   void ReportValueChanged(const std::string& key, uint32 flags) override;
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool ReadOnly() const override;
diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc
index d850150..f22f93a 100644
--- a/base/prefs/value_map_pref_store.cc
+++ b/base/prefs/value_map_pref_store.cc
@@ -29,9 +29,9 @@
 }
 
 void ValueMapPrefStore::SetValue(const std::string& key,
-                                 base::Value* value,
+                                 scoped_ptr<base::Value> value,
                                  uint32 flags) {
-  if (prefs_.SetValue(key, value))
+  if (prefs_.SetValue(key, value.Pass()))
     FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
 }
 
@@ -51,9 +51,9 @@
 }
 
 void ValueMapPrefStore::SetValueSilently(const std::string& key,
-                                         base::Value* value,
+                                         scoped_ptr<base::Value> value,
                                          uint32 flags) {
-  prefs_.SetValue(key, value);
+  prefs_.SetValue(key, value.Pass());
 }
 
 ValueMapPrefStore::~ValueMapPrefStore() {}
diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h
index 9d8fa3e..badfef7 100644
--- a/base/prefs/value_map_pref_store.h
+++ b/base/prefs/value_map_pref_store.h
@@ -29,13 +29,13 @@
 
   // WriteablePrefStore overrides:
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool GetMutableValue(const std::string& key, base::Value** value) override;
   void ReportValueChanged(const std::string& key, uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
 
  protected:
diff --git a/base/prefs/writeable_pref_store.h b/base/prefs/writeable_pref_store.h
index d85b4c8..cde3c84 100644
--- a/base/prefs/writeable_pref_store.h
+++ b/base/prefs/writeable_pref_store.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_store.h"
 
 namespace base {
@@ -30,10 +31,10 @@
 
   WriteablePrefStore() {}
 
-  // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
-  // must be non-NULL. |flags| is a bitmask of PrefWriteFlags.
+  // Sets a |value| for |key| in the store. |value| must be non-NULL. |flags| is
+  // a bitmask of PrefWriteFlags.
   virtual void SetValue(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) = 0;
 
   // Removes the value for |key|.
@@ -56,7 +57,7 @@
   // tests rely on the number of notifications generated. |flags| is a bitmask
   // of PrefWriteFlags.
   virtual void SetValueSilently(const std::string& key,
-                                base::Value* value,
+                                scoped_ptr<base::Value> value,
                                 uint32 flags) = 0;
 
  protected:
diff --git a/base/process/BUILD.gn b/base/process/BUILD.gn
index a362cbb..91f2725 100644
--- a/base/process/BUILD.gn
+++ b/base/process/BUILD.gn
@@ -77,7 +77,7 @@
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
-  if (is_nacl) {
+  if (is_nacl || is_ios) {
     sources -= [
       "kill.cc",
       "kill.h",
@@ -93,6 +93,10 @@
     ]
   }
 
+  if (is_ios) {
+    sources += [ "process_metrics.cc" ]
+  }
+
   configs += [ "//base:base_implementation" ]
 
   deps = [
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
index d2e9ec5..4f3fcac 100644
--- a/base/process/internal_linux.cc
+++ b/base/process/internal_linux.cc
@@ -25,8 +25,8 @@
 
 const char kStatFile[] = "stat";
 
-base::FilePath GetProcPidDir(pid_t pid) {
-  return base::FilePath(kProcDir).Append(IntToString(pid));
+FilePath GetProcPidDir(pid_t pid) {
+  return FilePath(kProcDir).Append(IntToString(pid));
 }
 
 pid_t ProcDirSlotToPid(const char* d_name) {
@@ -106,7 +106,7 @@
 
 typedef std::map<std::string, std::string> ProcStatMap;
 void ParseProcStat(const std::string& contents, ProcStatMap* output) {
-  base::StringPairs key_value_pairs;
+  StringPairs key_value_pairs;
   SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
   for (size_t i = 0; i < key_value_pairs.size(); ++i) {
     output->insert(key_value_pairs[i]);
diff --git a/base/process/launch.h b/base/process/launch.h
index 56f27a8..0e42cd0 100644
--- a/base/process/launch.h
+++ b/base/process/launch.h
@@ -297,7 +297,7 @@
 // binary. This should not be called in production/released code.
 BASE_EXPORT LaunchOptions LaunchOptionsForTest();
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
 // A wrapper for clone with fork-like behavior, meaning that it returns the
 // child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
 // as in the clone system call (the CLONE_VM flag is not supported).
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
index 77edc12..ed9faeb 100644
--- a/base/process/launch_posix.cc
+++ b/base/process/launch_posix.cc
@@ -65,6 +65,8 @@
 
 namespace base {
 
+#if !defined(OS_NACL_NONSFI)
+
 namespace {
 
 // Get the process's "environment" (i.e. the thing that setenv/getenv
@@ -188,55 +190,6 @@
 }
 #endif  // !defined(OS_LINUX) ||
         // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
-
-#if defined(OS_LINUX)
-bool IsRunningOnValgrind() {
-  return RUNNING_ON_VALGRIND;
-}
-
-// This function runs on the stack specified on the clone call. It uses longjmp
-// to switch back to the original stack so the child can return from sys_clone.
-int CloneHelper(void* arg) {
-  jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
-  longjmp(*env_ptr, 1);
-
-  // Should not be reached.
-  RAW_CHECK(false);
-  return 1;
-}
-
-// This function is noinline to ensure that stack_buf is below the stack pointer
-// that is saved when setjmp is called below. This is needed because when
-// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
-// upwards. See crbug.com/442912 for more details.
-#if defined(ADDRESS_SANITIZER)
-// Disable AddressSanitizer instrumentation for this function to make sure
-// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
-// Under ASan longjmp() will attempt to clean up the area between the old and
-// new stack pointers and print a warning that may confuse the user.
-__attribute__((no_sanitize_address))
-#endif
-NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
-                                      pid_t* ptid,
-                                      pid_t* ctid,
-                                      jmp_buf* env) {
-  // We use the libc clone wrapper instead of making the syscall
-  // directly because making the syscall may fail to update the libc's
-  // internal pid cache. The libc interface unfortunately requires
-  // specifying a new stack, so we use setjmp/longjmp to emulate
-  // fork-like behavior.
-  char stack_buf[PTHREAD_STACK_MIN];
-#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
-    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
-  // The stack grows downward.
-  void* stack = stack_buf + sizeof(stack_buf);
-#else
-#error "Unsupported architecture"
-#endif
-  return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
-}
-#endif  // defined(OS_LINUX)
-
 }  // anonymous namespace
 
 // Functor for |ScopedDIR| (below).
@@ -741,7 +694,60 @@
   return result == EXECUTE_SUCCESS;
 }
 
-#if defined(OS_LINUX)
+#endif  // !defined(OS_NACL_NONSFI)
+
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
+namespace {
+
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+// This function runs on the stack specified on the clone call. It uses longjmp
+// to switch back to the original stack so the child can return from sys_clone.
+int CloneHelper(void* arg) {
+  jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
+  longjmp(*env_ptr, 1);
+
+  // Should not be reached.
+  RAW_CHECK(false);
+  return 1;
+}
+
+// This function is noinline to ensure that stack_buf is below the stack pointer
+// that is saved when setjmp is called below. This is needed because when
+// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
+// upwards. See crbug.com/442912 for more details.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function to make sure
+// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
+// Under ASan longjmp() will attempt to clean up the area between the old and
+// new stack pointers and print a warning that may confuse the user.
+__attribute__((no_sanitize_address))
+#endif
+NOINLINE pid_t
+CloneAndLongjmpInChild(unsigned long flags,
+                       pid_t* ptid,
+                       pid_t* ctid,
+                       jmp_buf* env) {
+  // We use the libc clone wrapper instead of making the syscall
+  // directly because making the syscall may fail to update the libc's
+  // internal pid cache. The libc interface unfortunately requires
+  // specifying a new stack, so we use setjmp/longjmp to emulate
+  // fork-like behavior.
+  char stack_buf[PTHREAD_STACK_MIN];
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+  // The stack grows downward.
+  void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+  return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
+}
+
+}  // anonymous namespace
+
 pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
   const bool clone_tls_used = flags & CLONE_SETTLS;
   const bool invalid_ctid =
@@ -780,6 +786,6 @@
 
   return 0;
 }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_NACL_NONSFI)
 
 }  // namespace base
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
index ebc19b8..fa59f1a 100644
--- a/base/process/launch_win.cc
+++ b/base/process/launch_win.cc
@@ -238,7 +238,7 @@
   const string16 file = cmdline.GetProgram().value();
   const string16 arguments = cmdline.GetArgumentsString();
 
-  SHELLEXECUTEINFO shex_info = {0};
+  SHELLEXECUTEINFO shex_info = {};
   shex_info.cbSize = sizeof(shex_info);
   shex_info.fMask = SEE_MASK_NOCLOSEPROCESS;
   shex_info.hwnd = GetActiveWindow();
@@ -261,7 +261,7 @@
 }
 
 bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) {
-  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {};
   limit_info.BasicLimitInformation.LimitFlags = limit_flags;
   return 0 != SetInformationJobObject(
       job_object,
diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc
index 5b1e2ab..51427b3 100644
--- a/base/process/process_iterator_freebsd.cc
+++ b/base/process/process_iterator_freebsd.cc
@@ -9,6 +9,7 @@
 #include <unistd.h>
 
 #include "base/logging.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
 namespace base {
@@ -88,7 +89,8 @@
 
     std::string delimiters;
     delimiters.push_back('\0');
-    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+    entry_.cmd_line_args_ =
+        SplitString(data, delimiters, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     size_t exec_name_end = data.find('\0');
     if (exec_name_end == std::string::npos) {
diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc
index 3319552..5c8ca08 100644
--- a/base/process/process_iterator_linux.cc
+++ b/base/process/process_iterator_linux.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/process/internal_linux.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
 
@@ -48,7 +49,8 @@
     return false;
   std::string delimiters;
   delimiters.push_back('\0');
-  Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+  *proc_cmd_line_args =
+      SplitString(cmd_line, delimiters, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
   return true;
 }
 
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
index e35c2ae..add62d5 100644
--- a/base/process/process_iterator_mac.cc
+++ b/base/process/process_iterator_mac.cc
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "base/logging.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
 namespace base {
@@ -99,7 +100,8 @@
     // |entry_.cmd_line_args_|.
     std::string delimiters;
     delimiters.push_back('\0');
-    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+    entry_.cmd_line_args_ =
+        SplitString(data, delimiters, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     // |data| starts with the full executable path followed by a null character.
     // We search for the first instance of '\0' and extract everything before it
diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc
index 7c44eb1..b0d52b8 100644
--- a/base/process/process_iterator_openbsd.cc
+++ b/base/process/process_iterator_openbsd.cc
@@ -8,6 +8,7 @@
 #include <sys/sysctl.h>
 
 #include "base/logging.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
 namespace base {
@@ -92,7 +93,8 @@
     // |entry_.cmd_line_args_|.
     std::string delimiters;
     delimiters.push_back('\0');
-    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+    entry_.cmd_line_args_ =
+        SplitString(data, delimiters, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     // |data| starts with the full executable path followed by a null character.
     // We search for the first instance of '\0' and extract everything before it
diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc
index 88a310e..6e10dd2 100644
--- a/base/process/process_linux.cc
+++ b/base/process/process_linux.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
@@ -119,7 +120,7 @@
 
 #if defined(OS_CHROMEOS)
   if (cgroups.Get().enabled) {
-    std::string pid = StringPrintf("%d", process_);
+    std::string pid = IntToString(process_);
     const base::FilePath file =
         background ?
             cgroups.Get().background_file : cgroups.Get().foreground_file;
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index 5916b94..8b4ec86 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -140,7 +140,8 @@
   // memory usage as per definition of CommittedBytes.
   void GetCommittedKBytes(CommittedKBytes* usage) const;
   // Fills a WorkingSetKBytes containing resident private and shared memory
-  // usage in bytes, as per definition of WorkingSetBytes.
+  // usage in bytes, as per definition of WorkingSetBytes. Note that this
+  // function is somewhat expensive on Windows (a few ms per process).
   bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
 
 #if defined(OS_MACOSX)
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index c564a67..0da1ec3 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -563,17 +563,15 @@
   // MemTotal value
   meminfo->total = 0;
 
-  std::vector<std::string> meminfo_lines;
-  Tokenize(meminfo_data, "\n", &meminfo_lines);
-  for (std::vector<std::string>::iterator it = meminfo_lines.begin();
-       it != meminfo_lines.end(); ++it) {
-    std::vector<std::string> tokens;
-    SplitStringAlongWhitespace(*it, &tokens);
+  for (const StringPiece& line : SplitStringPiece(
+           meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    std::vector<StringPiece> tokens = SplitStringPiece(
+        line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
     // HugePages_* only has a number and no suffix so we can't rely on
     // there being exactly 3 tokens.
     if (tokens.size() <= 1) {
       DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
-                    << " malformed line: " << *it;
+                    << " malformed line: " << line.as_string();
       continue;
     }
 
@@ -630,12 +628,10 @@
   // We iterate through the whole file because the position of the
   // fields are dependent on the kernel version and configuration.
 
-  std::vector<std::string> vmstat_lines;
-  Tokenize(vmstat_data, "\n", &vmstat_lines);
-  for (std::vector<std::string>::iterator it = vmstat_lines.begin();
-       it != vmstat_lines.end(); ++it) {
-    std::vector<std::string> tokens;
-    SplitString(*it, ' ', &tokens);
+  for (const StringPiece& line : SplitStringPiece(
+           vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    std::vector<StringPiece> tokens =
+        SplitStringPiece(line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
     if (tokens.size() != 2)
       continue;
 
@@ -792,9 +788,9 @@
     return false;
   }
 
-  std::vector<std::string> diskinfo_lines;
-  size_t line_count = Tokenize(diskinfo_data, "\n", &diskinfo_lines);
-  if (line_count == 0) {
+  std::vector<StringPiece> diskinfo_lines = SplitStringPiece(
+      diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  if (diskinfo_lines.size() == 0) {
     DLOG(WARNING) << "No lines found";
     return false;
   }
@@ -823,12 +819,12 @@
   uint64 io_time = 0;
   uint64 weighted_io_time = 0;
 
-  for (size_t i = 0; i < line_count; i++) {
-    std::vector<std::string> disk_fields;
-    SplitStringAlongWhitespace(diskinfo_lines[i], &disk_fields);
+  for (const StringPiece& line : diskinfo_lines) {
+    std::vector<StringPiece> disk_fields = SplitStringPiece(
+        line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     // Fields may have overflowed and reset to zero.
-    if (IsValidDiskName(disk_fields[kDiskDriveName])) {
+    if (IsValidDiskName(disk_fields[kDiskDriveName].as_string())) {
       StringToUint64(disk_fields[kDiskReads], &reads);
       StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
       StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc
index 6c424e3..170f6dc 100644
--- a/base/process/process_metrics_win.cc
+++ b/base/process/process_metrics_win.cc
@@ -260,7 +260,7 @@
           GetProcAddress(psapi_dll, "GetPerformanceInfo"));
 
     if (!GetPerformanceInfo_func) {
-      // The function could be loaded!
+      // The function could not be loaded!
       memset(pPerformanceInformation, 0, cb);
       return FALSE;
     }
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
index 47b0d5b..b6f22c1 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -295,9 +295,10 @@
 
 #if !defined(OS_NACL_NONSFI)
 bool Process::Terminate(int exit_code, bool wait) const {
-  // result_code isn't supportable.
+  // exit_code isn't supportable.
   DCHECK(IsValid());
-  DCHECK_GT(process_, 1);
+  CHECK_GT(process_, 0);
+
   bool result = kill(process_, SIGTERM) == 0;
   if (result && wait) {
     int tries = 60;
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 1f7f1b2..6c1a3f1 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -64,6 +64,12 @@
 
 namespace {
 
+const char kSignalFileSlow[] = "SlowChildProcess.die";
+const char kSignalFileKill[] = "KilledChildProcess.die";
+
+#if defined(OS_POSIX)
+const char kSignalFileTerm[] = "TerminatedChildProcess.die";
+
 #if defined(OS_ANDROID)
 const char kShellPath[] = "/system/bin/sh";
 const char kPosixShell[] = "sh";
@@ -71,13 +77,7 @@
 const char kShellPath[] = "/bin/sh";
 const char kPosixShell[] = "bash";
 #endif
-
-const char kSignalFileSlow[] = "SlowChildProcess.die";
-const char kSignalFileKill[] = "KilledChildProcess.die";
-
-#if defined(OS_POSIX)
-const char kSignalFileTerm[] = "TerminatedChildProcess.die";
-#endif
+#endif  // defined(OS_POSIX)
 
 #if defined(OS_WIN)
 const int kExpectedStillRunningExitCode = 0x102;
@@ -1025,6 +1025,7 @@
   return kSuccess;
 }
 
+#if defined(CLONE_NEWUSER) && defined(CLONE_NEWPID)
 TEST_F(ProcessUtilTest, CloneFlags) {
   if (RunningOnValgrind() ||
       !base::PathExists(FilePath("/proc/self/ns/user")) ||
@@ -1043,6 +1044,7 @@
   EXPECT_TRUE(process.WaitForExit(&exit_code));
   EXPECT_EQ(kSuccess, exit_code);
 }
+#endif
 
 TEST(ForkWithFlagsTest, UpdatesPidCache) {
   // The libc clone function, which allows ForkWithFlags to keep the pid cache
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
index 2ad72c7..30cd9dc 100644
--- a/base/process/process_win.cc
+++ b/base/process/process_win.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/process/kill.h"
+#include "base/strings/string_util.h"
 #include "base/win/windows_version.h"
 
 namespace {
@@ -189,8 +190,10 @@
     DWORD background_priority = IDLE_PRIORITY_CLASS;
     base::FieldTrial* trial =
         base::FieldTrialList::Find("BackgroundRendererProcesses");
-    if (trial && trial->group_name() == "AllowBelowNormalFromBrowser")
+    if (trial && StartsWith(trial->group_name(), "AllowBelowNormalFromBrowser",
+                            CompareCase::SENSITIVE)) {
       background_priority = BELOW_NORMAL_PRIORITY_CLASS;
+    }
 
     priority = value ? background_priority : NORMAL_PRIORITY_CLASS;
   }
diff --git a/base/profiler/stack_sampling_profiler_win.cc b/base/profiler/stack_sampling_profiler_win.cc
index 1ccd134..73b8e11 100644
--- a/base/profiler/stack_sampling_profiler_win.cc
+++ b/base/profiler/stack_sampling_profiler_win.cc
@@ -40,7 +40,7 @@
     instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
 
     if (runtime_function) {
-      KNONVOLATILE_CONTEXT_POINTERS nvcontext = {0};
+      KNONVOLATILE_CONTEXT_POINTERS nvcontext = {};
       void* handler_data;
       ULONG64 establisher_frame;
       RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
diff --git a/base/strings/pattern.cc b/base/strings/pattern.cc
new file mode 100644
index 0000000..56915fe
--- /dev/null
+++ b/base/strings/pattern.cc
@@ -0,0 +1,171 @@
+// 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/strings/pattern.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+static bool IsWildcard(base_icu::UChar32 character) {
+  return character == '*' || character == '?';
+}
+
+// Move the strings pointers to the point where they start to differ.
+template <typename CHAR, typename NEXT>
+static void EatSameChars(const CHAR** pattern,
+                         const CHAR* pattern_end,
+                         const CHAR** string,
+                         const CHAR* string_end,
+                         NEXT next) {
+  const CHAR* escape = NULL;
+  while (*pattern != pattern_end && *string != string_end) {
+    if (!escape && IsWildcard(**pattern)) {
+      // We don't want to match wildcard here, except if it's escaped.
+      return;
+    }
+
+    // Check if the escapement char is found. If so, skip it and move to the
+    // next character.
+    if (!escape && **pattern == '\\') {
+      escape = *pattern;
+      next(pattern, pattern_end);
+      continue;
+    }
+
+    // Check if the chars match, if so, increment the ptrs.
+    const CHAR* pattern_next = *pattern;
+    const CHAR* string_next = *string;
+    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+    if (pattern_char == next(&string_next, string_end) &&
+        pattern_char != CBU_SENTINEL) {
+      *pattern = pattern_next;
+      *string = string_next;
+    } else {
+      // Uh oh, it did not match, we are done. If the last char was an
+      // escapement, that means that it was an error to advance the ptr here,
+      // let's put it back where it was. This also mean that the MatchPattern
+      // function will return false because if we can't match an escape char
+      // here, then no one will.
+      if (escape) {
+        *pattern = escape;
+      }
+      return;
+    }
+
+    escape = NULL;
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+  while (*pattern != end) {
+    if (!IsWildcard(**pattern))
+      return;
+    next(pattern, end);
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static bool MatchPatternT(const CHAR* eval,
+                          const CHAR* eval_end,
+                          const CHAR* pattern,
+                          const CHAR* pattern_end,
+                          int depth,
+                          NEXT next) {
+  const int kMaxDepth = 16;
+  if (depth > kMaxDepth)
+    return false;
+
+  // Eat all the matching chars.
+  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
+
+  // If the string is empty, then the pattern must be empty too, or contains
+  // only wildcards.
+  if (eval == eval_end) {
+    EatWildcard(&pattern, pattern_end, next);
+    return pattern == pattern_end;
+  }
+
+  // Pattern is empty but not string, this is not a match.
+  if (pattern == pattern_end)
+    return false;
+
+  // If this is a question mark, then we need to compare the rest with
+  // the current string or the string with one character eaten.
+  const CHAR* next_pattern = pattern;
+  next(&next_pattern, pattern_end);
+  if (pattern[0] == '?') {
+    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end, depth + 1,
+                      next))
+      return true;
+    const CHAR* next_eval = eval;
+    next(&next_eval, eval_end);
+    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end, depth + 1,
+                      next))
+      return true;
+  }
+
+  // This is a *, try to match all the possible substrings with the remainder
+  // of the pattern.
+  if (pattern[0] == '*') {
+    // Collapse duplicate wild cards (********** into *) so that the
+    // method does not recurse unnecessarily. http://crbug.com/52839
+    EatWildcard(&next_pattern, pattern_end, next);
+
+    while (eval != eval_end) {
+      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end, depth + 1,
+                        next))
+        return true;
+      eval++;
+    }
+
+    // We reached the end of the string, let see if the pattern contains only
+    // wildcards.
+    if (eval == eval_end) {
+      EatWildcard(&pattern, pattern_end, next);
+      if (pattern != pattern_end)
+        return false;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+struct NextCharUTF8 {
+  base_icu::UChar32 operator()(const char** p, const char* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU8_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+struct NextCharUTF16 {
+  base_icu::UChar32 operator()(const char16** p, const char16* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU16_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+}  // namespace
+
+bool MatchPattern(const StringPiece& eval, const StringPiece& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(), pattern.data(),
+                       pattern.data() + pattern.size(), 0, NextCharUTF8());
+}
+
+bool MatchPattern(const StringPiece16& eval, const StringPiece16& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(), pattern.data(),
+                       pattern.data() + pattern.size(), 0, NextCharUTF16());
+}
+
+}  // namespace base
diff --git a/base/strings/pattern.h b/base/strings/pattern.h
new file mode 100644
index 0000000..b698207
--- /dev/null
+++ b/base/strings/pattern.h
@@ -0,0 +1,26 @@
+// 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_STRINGS_PATTERN_H_
+#define BASE_STRINGS_PATTERN_H_
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Returns true if the string passed in matches the pattern. The pattern
+// string can contain wildcards like * and ?
+//
+// The backslash character (\) is an escape character for * and ?
+// We limit the patterns to having a max of 16 * or ? characters.
+// ? matches 0 or 1 character, while * matches 0 or more characters.
+BASE_EXPORT bool MatchPattern(const StringPiece& string,
+                              const StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const StringPiece16& string,
+                              const StringPiece16& pattern);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_PATTERN_H_
diff --git a/base/strings/pattern_unittest.cc b/base/strings/pattern_unittest.cc
new file mode 100644
index 0000000..affd1d2
--- /dev/null
+++ b/base/strings/pattern_unittest.cc
@@ -0,0 +1,50 @@
+// 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/strings/pattern.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(StringUtilTest, MatchPatternTest) {
+  EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
+  EXPECT_TRUE(MatchPattern("www.google.com", "*"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
+  EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
+  EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
+  EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
+  EXPECT_FALSE(MatchPattern("", "*.*"));
+  EXPECT_TRUE(MatchPattern("", "*"));
+  EXPECT_TRUE(MatchPattern("", "?"));
+  EXPECT_TRUE(MatchPattern("", ""));
+  EXPECT_FALSE(MatchPattern("Hello", ""));
+  EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
+  // Stop after a certain recursion depth.
+  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+
+  // Test UTF8 matching.
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
+  EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
+  // Invalid sequences should be handled as a single invalid character.
+  EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
+  // If the pattern has invalid characters, it shouldn't match anything.
+  EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
+
+  // Test UTF16 character matching.
+  EXPECT_TRUE(
+      MatchPattern(UTF8ToUTF16("www.google.com"), UTF8ToUTF16("*.com")));
+  EXPECT_TRUE(
+      MatchPattern(UTF8ToUTF16("Hello*1234"), UTF8ToUTF16("He??o\\*1*")));
+
+  // This test verifies that consecutive wild cards are collapsed into 1
+  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
+  // recursion depth).
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
+                           UTF8ToUTF16("He********************************o")));
+}
+
+}  // namespace base
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc
index 642d24e..b6b65d2 100644
--- a/base/strings/string_number_conversions.cc
+++ b/base/strings/string_number_conversions.cc
@@ -42,7 +42,12 @@
   template <typename INT2, typename UINT2>
   struct ToUnsignedT<INT2, UINT2, true> {
     static UINT2 ToUnsigned(INT2 value) {
-      return static_cast<UINT2>(value < 0 ? -value : value);
+      if (value >= 0) {
+        return value;
+      } else {
+        // Avoid integer overflow when negating INT_MIN.
+        return static_cast<UINT2>(-(value + 1)) + 1;
+      }
     }
   };
 
@@ -131,10 +136,10 @@
   return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
 }
 
-// There is an IsWhitespace for wchars defined in string_util.h, but it is
-// locale independent, whereas the functions we are replacing were
-// locale-dependent. TBD what is desired, but for the moment let's not introduce
-// a change in behaviour.
+// There is an IsUnicodeWhitespace for wchars defined in string_util.h, but it
+// is locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not
+// introduce a change in behaviour.
 template<typename CHAR> class WhitespaceHelper {
 };
 
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index 349018b..a83b7d8 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -18,12 +18,6 @@
 // Both of these have the same lifetime semantics.  Passing by value
 // generates slightly smaller code.  For more discussion, Googlers can see
 // the thread go/stringpiecebyvalue on c-users.
-//
-// StringPiece16 is similar to StringPiece but for base::string16 instead of
-// std::string. We do not define as large of a subset of the STL functions
-// from basic_string as in StringPiece, but this can be changed if these
-// functions (find, find_first_of, etc.) are found to be useful in this context.
-//
 
 #ifndef BASE_STRINGS_STRING_PIECE_H_
 #define BASE_STRINGS_STRING_PIECE_H_
diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc
index 88a6236..8998c81 100644
--- a/base/strings/string_split.cc
+++ b/base/strings/string_split.cc
@@ -12,26 +12,93 @@
 
 namespace {
 
-template <typename STR>
-void SplitStringT(const STR& str,
-                  const typename STR::value_type s,
-                  bool trim_whitespace,
-                  std::vector<STR>* r) {
-  r->clear();
-  size_t last = 0;
-  size_t c = str.size();
-  for (size_t i = 0; i <= c; ++i) {
-    if (i == c || str[i] == s) {
-      STR tmp(str, last, i - last);
-      if (trim_whitespace)
-        TrimWhitespace(tmp, TRIM_ALL, &tmp);
-      // Avoid converting an empty or all-whitespace source string into a vector
-      // of one empty string.
-      if (i != c || !r->empty() || !tmp.empty())
-        r->push_back(tmp);
-      last = i + 1;
+// PieceToOutputType converts a StringPiece as needed to a given output type,
+// which is either the same type of StringPiece (a NOP) or the corresponding
+// non-piece string type.
+//
+// The default converter is a NOP, it works when the OutputType is the
+// correct StringPiece.
+template <typename Str, typename OutputType>
+OutputType PieceToOutputType(BasicStringPiece<Str> piece) {
+  return piece;
+}
+template <>  // Convert StringPiece to std::string
+std::string PieceToOutputType<std::string, std::string>(StringPiece piece) {
+  return piece.as_string();
+}
+template <>  // Convert StringPiece16 to string16.
+string16 PieceToOutputType<string16, string16>(StringPiece16 piece) {
+  return piece.as_string();
+}
+
+// Returns either the ASCII or UTF-16 whitespace.
+template <typename Str>
+BasicStringPiece<Str> WhitespaceForType();
+template <>
+StringPiece16 WhitespaceForType<string16>() {
+  return kWhitespaceUTF16;
+}
+template <>
+StringPiece WhitespaceForType<std::string>() {
+  return kWhitespaceASCII;
+}
+
+// Optimize the single-character case to call find() on the string instead,
+// since this is the common case and can be made faster. This could have been
+// done with template specialization too, but would have been less clear.
+//
+// There is no corresponding FindFirstNotOf because StringPiece already
+// implements these different versions that do the optimized searching.
+size_t FindFirstOf(StringPiece piece, char c, size_t pos) {
+  return piece.find(c, pos);
+}
+size_t FindFirstOf(StringPiece16 piece, char16 c, size_t pos) {
+  return piece.find(c, pos);
+}
+size_t FindFirstOf(StringPiece piece, StringPiece one_of, size_t pos) {
+  return piece.find_first_of(one_of, pos);
+}
+size_t FindFirstOf(StringPiece16 piece, StringPiece16 one_of, size_t pos) {
+  return piece.find_first_of(one_of, pos);
+}
+
+// General string splitter template. Can take 8- or 16-bit input, can produce
+// the corresponding string or StringPiece output, and can take single- or
+// multiple-character delimiters.
+//
+// DelimiterType is either a character (Str::value_type) or a string piece of
+// multiple characters (BasicStringPiece<Str>). StringPiece has a version of
+// find for both of these cases, and the single-character version is the most
+// common and can be implemented faster, which is why this is a template.
+template <typename Str, typename OutputStringType, typename DelimiterType>
+static std::vector<OutputStringType> SplitStringT(BasicStringPiece<Str> str,
+                                                  DelimiterType delimiter,
+                                                  WhitespaceHandling whitespace,
+                                                  SplitResult result_type) {
+  std::vector<OutputStringType> result;
+  if (str.empty())
+    return result;
+
+  size_t start = 0;
+  while (start != Str::npos) {
+    size_t end = FindFirstOf(str, delimiter, start);
+
+    BasicStringPiece<Str> piece;
+    if (end == Str::npos) {
+      piece = str.substr(start);
+      start = Str::npos;
+    } else {
+      piece = str.substr(start, end - start);
+      start = end + 1;
     }
+
+    if (whitespace == TRIM_WHITESPACE)
+      piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL);
+
+    if (result_type == SPLIT_WANT_ALL || !piece.empty())
+      result.push_back(PieceToOutputType<Str, OutputStringType>(piece));
   }
+  return result;
 }
 
 bool SplitStringIntoKeyValue(const std::string& line,
@@ -62,8 +129,8 @@
 
 template <typename STR>
 void SplitStringUsingSubstrT(const STR& str,
-                                    const STR& s,
-                                    std::vector<STR>* r) {
+                             const STR& s,
+                             std::vector<STR>* r) {
   r->clear();
   typename STR::size_type begin_index = 0;
   while (true) {
@@ -83,64 +150,86 @@
   }
 }
 
-template<typename STR>
-void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) {
-  result->clear();
-  const size_t length = str.length();
-  if (!length)
-    return;
-
-  bool last_was_ws = false;
-  size_t last_non_ws_start = 0;
-  for (size_t i = 0; i < length; ++i) {
-    switch (str[i]) {
-      // HTML 5 defines whitespace as: space, tab, LF, line tab, FF, or CR.
-      case L' ':
-      case L'\t':
-      case L'\xA':
-      case L'\xB':
-      case L'\xC':
-      case L'\xD':
-        if (!last_was_ws) {
-          if (i > 0) {
-            result->push_back(
-                str.substr(last_non_ws_start, i - last_non_ws_start));
-          }
-          last_was_ws = true;
-        }
-        break;
-
-      default:  // Not a space character.
-        if (last_was_ws) {
-          last_was_ws = false;
-          last_non_ws_start = i;
-        }
-        break;
-    }
-  }
-  if (!last_was_ws) {
-    result->push_back(
-        str.substr(last_non_ws_start, length - last_non_ws_start));
-  }
-}
-
 }  // namespace
 
-void SplitString(const string16& str,
-                 char16 c,
-                 std::vector<string16>* r) {
+std::vector<std::string> SplitString(StringPiece input,
+                                     StringPiece separators,
+                                     WhitespaceHandling whitespace,
+                                     SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<std::string, std::string, char>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<std::string, std::string, StringPiece>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<string16> SplitString(StringPiece16 input,
+                                  StringPiece16 separators,
+                                  WhitespaceHandling whitespace,
+                                  SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<string16, string16, char16>(input, separators[0],
+                                                    whitespace, result_type);
+  }
+  return SplitStringT<string16, string16, StringPiece16>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece> SplitStringPiece(StringPiece input,
+                                          StringPiece separators,
+                                          WhitespaceHandling whitespace,
+                                          SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<std::string, StringPiece, char>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<std::string, StringPiece, StringPiece>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece16> SplitStringPiece(StringPiece16 input,
+                                            StringPiece16 separators,
+                                            WhitespaceHandling whitespace,
+                                            SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<string16, StringPiece16, char16>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<string16, StringPiece16, StringPiece16>(
+      input, separators, whitespace, result_type);
+}
+
+void SplitString(const string16& str, char16 c, std::vector<string16>* result) {
   DCHECK(CBU16_IS_SINGLE(c));
-  SplitStringT(str, c, true, r);
+  *result = SplitStringT<string16, string16, char16>(str, c, TRIM_WHITESPACE,
+                                                     SPLIT_WANT_ALL);
+
+  // Backward-compat hack: The old SplitString implementation would keep
+  // empty substrings, for example:
+  //    "a,,b" -> ["a", "", "b"]
+  //    "a, ,b" -> ["a", "", "b"]
+  // which the current code also does. But the old one would discard them when
+  // the only result was that empty string:
+  //    "  " -> []
+  // In the latter case, our new code will give [""]
+  if (result->size() == 1 && (*result)[0].empty())
+    result->clear();
 }
 
 void SplitString(const std::string& str,
                  char c,
-                 std::vector<std::string>* r) {
+                 std::vector<std::string>* result) {
 #if CHAR_MIN < 0
   DCHECK_GE(c, 0);
 #endif
   DCHECK_LT(c, 0x7F);
-  SplitStringT(str, c, true, r);
+  *result = SplitStringT<std::string, std::string, char>(
+      str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL);
+
+  // Backward-compat hack, see above.
+  if (result->size() == 1 && (*result)[0].empty())
+    result->clear();
 }
 
 bool SplitStringIntoKeyValuePairs(const std::string& line,
@@ -182,31 +271,36 @@
   SplitStringUsingSubstrT(str, s, r);
 }
 
-void SplitStringDontTrim(const string16& str,
+void SplitStringDontTrim(StringPiece16 str,
                          char16 c,
-                         std::vector<string16>* r) {
+                         std::vector<string16>* result) {
   DCHECK(CBU16_IS_SINGLE(c));
-  SplitStringT(str, c, false, r);
+  *result = SplitStringT<string16, string16, char16>(str, c, KEEP_WHITESPACE,
+                                                     SPLIT_WANT_ALL);
 }
 
-void SplitStringDontTrim(const std::string& str,
+void SplitStringDontTrim(StringPiece str,
                          char c,
-                         std::vector<std::string>* r) {
+                         std::vector<std::string>* result) {
 #if CHAR_MIN < 0
   DCHECK_GE(c, 0);
 #endif
   DCHECK_LT(c, 0x7F);
-  SplitStringT(str, c, false, r);
+  *result = SplitStringT<std::string, std::string, char>(
+      str, c, KEEP_WHITESPACE, SPLIT_WANT_ALL);
 }
 
 void SplitStringAlongWhitespace(const string16& str,
                                 std::vector<string16>* result) {
-  SplitStringAlongWhitespaceT(str, result);
+  *result = SplitStringT<string16, string16, StringPiece16>(
+      str, StringPiece16(kWhitespaceASCIIAs16), TRIM_WHITESPACE,
+      SPLIT_WANT_NONEMPTY);
 }
 
 void SplitStringAlongWhitespace(const std::string& str,
                                 std::vector<std::string>* result) {
-  SplitStringAlongWhitespaceT(str, result);
+  *result = SplitStringT<std::string, std::string, StringPiece>(
+      str, StringPiece(kWhitespaceASCII), TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
 }
 
 }  // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
index 55d8cb3..1f20571 100644
--- a/base/strings/string_split.h
+++ b/base/strings/string_split.h
@@ -11,9 +11,100 @@
 
 #include "base/base_export.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
 
 namespace base {
 
+enum WhitespaceHandling {
+  KEEP_WHITESPACE,
+  TRIM_WHITESPACE,
+};
+
+enum SplitResult {
+  // Strictly return all results.
+  //
+  // If the input is ",," and the separator is ',' this will return a
+  // vector of three empty strings.
+  SPLIT_WANT_ALL,
+
+  // Only nonempty results will be added to the results. Multiple separators
+  // will be coalesced. Separators at the beginning and end of the input will
+  // be ignored. With TRIM_WHITESPACE, whitespace-only results will be dropped.
+  //
+  // If the input is ",," and the separator is ',', this will return an empty
+  // vector.
+  SPLIT_WANT_NONEMPTY,
+};
+
+// Split the given string on ANY of the given separators, returning copies of
+// the result.
+//
+// To split on either commas or semicolons, keeping all whitespace:
+//
+//   std::vector<std::string> tokens = base::SplitString(
+//       input, ",;", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+BASE_EXPORT std::vector<std::string> SplitString(StringPiece input,
+                                                 StringPiece separators,
+                                                 WhitespaceHandling whitespace,
+                                                 SplitResult result_type);
+BASE_EXPORT std::vector<string16> SplitString(StringPiece16 input,
+                                              StringPiece16 separators,
+                                              WhitespaceHandling whitespace,
+                                              SplitResult result_type);
+
+// Like SplitString above except it returns a vector of StringPieces which
+// reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
+//
+// To iterate through all whitespace-separated tokens in an input string:
+//
+//   for (const auto& cur :
+//        base::SplitStringPiece(input, base::kWhitespaceASCII,
+//                               base::KEEP_WHITESPACE,
+//                               base::SPLIT_WANT_NONEMPTY)) {
+//     ...
+BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
+    StringPiece input,
+    StringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
+    StringPiece16 input,
+    StringPiece16 separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+
+using StringPairs = std::vector<std::pair<std::string, std::string>>;
+
+// Splits |line| into key value pairs according to the given delimiters and
+// removes whitespace leading each key and trailing each value. Returns true
+// only if each pair has a non-empty key and value. |key_value_pairs| will
+// include ("","") pairs for entries without |key_value_delimiter|.
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
+                                              char key_value_delimiter,
+                                              char key_value_pair_delimiter,
+                                              StringPairs* key_value_pairs);
+
+// Similar to SplitString, but use a substring delimiter instead of a list of
+// characters that are all possible delimiters.
+//
+// TODO(brettw) this should probably be changed and expanded to provide a
+// mirror of the SplitString[Piece] API above, just with the different
+// delimiter handling.
+BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
+                                        const string16& s,
+                                        std::vector<string16>* r);
+BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
+                                        const std::string& s,
+                                        std::vector<std::string>* r);
+
+// -----------------------------------------------------------------------------
+// Backwards-compat wrappers
+//
+// New code should use one of the more general variants above.
+// TODO(brettw) remove these and convert to the versions above.
+
 // Splits |str| into a vector of strings delimited by |c|, placing the results
 // in |r|. If several instances of |c| are contiguous, or if |str| begins with
 // or ends with |c|, then an empty string is inserted.
@@ -32,46 +123,29 @@
                              char c,
                              std::vector<std::string>* r);
 
-typedef std::vector<std::pair<std::string, std::string> > StringPairs;
-
-// Splits |line| into key value pairs according to the given delimiters and
-// removes whitespace leading each key and trailing each value. Returns true
-// only if each pair has a non-empty key and value. |key_value_pairs| will
-// include ("","") pairs for entries without |key_value_delimiter|.
-BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
-                                              char key_value_delimiter,
-                                              char key_value_pair_delimiter,
-                                              StringPairs* key_value_pairs);
-
-// The same as SplitString, but use a substring delimiter instead of a char.
-BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
-                                        const string16& s,
-                                        std::vector<string16>* r);
-BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
-                                        const std::string& s,
-                                        std::vector<std::string>* r);
-
 // The same as SplitString, but don't trim white space.
 // NOTE: |c| must be in BMP (Basic Multilingual Plane)
-BASE_EXPORT void SplitStringDontTrim(const string16& str,
+BASE_EXPORT void SplitStringDontTrim(StringPiece16 str,
                                      char16 c,
                                      std::vector<string16>* r);
 // |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
 // the trailing byte of a multi-byte character can be in the ASCII range.
 // UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
 // Note: |c| must be in the ASCII range.
-BASE_EXPORT void SplitStringDontTrim(const std::string& str,
+BASE_EXPORT void SplitStringDontTrim(StringPiece str,
                                      char c,
-                                     std::vector<std::string>* r);
+                                     std::vector<std::string>* result);
 
-// WARNING: this uses whitespace as defined by the HTML5 spec. If you need
-// a function similar to this but want to trim all types of whitespace, then
-// factor this out into a function that takes a string containing the characters
-// that are treated as whitespace.
+// WARNING: this uses whitespace as defined by the HTML5 spec (ASCII whitespace
+// only).
 //
-// Splits the string along whitespace (where whitespace is the five space
-// characters defined by HTML 5). Each contiguous block of non-whitespace
-// characters is added to result.
+// The difference between this and calling SplitString with the whitespace
+// characters as separators is the treatment of the first element when the
+// string starts with whitespace.
+//
+// Input        SplitString      SplitStringAlongWhitespace
+// --------------------------------------------------------
+// " a "        "", "a"          "a"
 BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
                                             std::vector<string16>* result);
 BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc
index 32bbe28..c745ab5 100644
--- a/base/strings/string_split_unittest.cc
+++ b/base/strings/string_split_unittest.cc
@@ -169,7 +169,81 @@
   EXPECT_THAT(results, ElementsAre(""));
 }
 
-TEST(StringUtilTest, SplitString) {
+TEST(StringUtilTest, SplitString_Basics) {
+  std::vector<std::string> r;
+
+  r = SplitString(std::string(), ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  EXPECT_TRUE(r.empty());
+
+  // Empty separator list
+  r = SplitString("hello, world", "", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, r.size());
+  EXPECT_EQ("hello, world", r[0]);
+
+  // Should split on any of the separators.
+  r = SplitString("::,,;;", ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(7u, r.size());
+  for (auto str : r)
+    ASSERT_TRUE(str.empty());
+
+  r = SplitString("red, green; blue:", ",:;", TRIM_WHITESPACE,
+                  SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("red", r[0]);
+  EXPECT_EQ("green", r[1]);
+  EXPECT_EQ("blue", r[2]);
+
+  // Want to split a string along whitespace sequences.
+  r = SplitString("  red green   \tblue\n", " \t\n", TRIM_WHITESPACE,
+                  SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("red", r[0]);
+  EXPECT_EQ("green", r[1]);
+  EXPECT_EQ("blue", r[2]);
+
+  // Weird case of splitting on spaces but not trimming.
+  r = SplitString(" red ", " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);  // Before the first space.
+  EXPECT_EQ("red", r[1]);
+  EXPECT_EQ("", r[2]);  // After the last space.
+}
+
+TEST(StringUtilTest, SplitString_WhitespaceAndResultType) {
+  std::vector<std::string> r;
+
+  // Empty input handling.
+  r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  EXPECT_TRUE(r.empty());
+  r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  EXPECT_TRUE(r.empty());
+
+  // Input string is space and we're trimming.
+  r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, r.size());
+  EXPECT_EQ("", r[0]);
+  r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  EXPECT_TRUE(r.empty());
+
+  // Test all 4 combinations of flags on ", ,".
+  r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);
+  EXPECT_EQ(" ", r[1]);
+  EXPECT_EQ("", r[2]);
+  r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(1u, r.size());
+  ASSERT_EQ(" ", r[0]);
+  r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);
+  EXPECT_EQ("", r[1]);
+  EXPECT_EQ("", r[2]);
+  r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  ASSERT_TRUE(r.empty());
+}
+
+TEST(StringUtilTest, SplitString_Legacy) {
   std::vector<std::wstring> r;
 
   SplitString(std::wstring(), L',', &r);
@@ -197,6 +271,13 @@
   EXPECT_EQ(r[2], L"c");
   r.clear();
 
+  SplitString(L"a, ,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
   SplitString(L"   ", L'*', &r);
   EXPECT_EQ(0U, r.size());
   r.clear();
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index cc77693..3317740 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -21,14 +21,13 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/third_party/icu/icu_utf.h"
 #include "build/build_config.h"
 
-// Remove when this entire file is in the base namespace.
-using base::char16;
-using base::string16;
+namespace base {
 
 namespace {
 
@@ -79,14 +78,16 @@
 }
 
 template<size_t size, typename CharacterType> struct NonASCIIMask;
-template<> struct NonASCIIMask<4, base::char16> {
-    static inline uint32_t value() { return 0xFF80FF80U; }
+template <>
+struct NonASCIIMask<4, char16> {
+  static inline uint32_t value() { return 0xFF80FF80U; }
 };
 template<> struct NonASCIIMask<4, char> {
     static inline uint32_t value() { return 0x80808080U; }
 };
-template<> struct NonASCIIMask<8, base::char16> {
-    static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
+template <>
+struct NonASCIIMask<8, char16> {
+  static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
 };
 template<> struct NonASCIIMask<8, char> {
     static inline uint64_t value() { return 0x8080808080808080ULL; }
@@ -100,9 +101,17 @@
 };
 #endif  // WCHAR_T_IS_UTF32
 
-}  // namespace
+// DO NOT USE. http://crbug.com/24917
+//
+// tolower() will given incorrect results for non-ASCII characters. Use the
+// ASCII version, base::i18n::ToLower, or base::i18n::FoldCase. This is here
+// for backwards-compat for StartsWith until such calls can be updated.
+struct CaseInsensitiveCompareDeprecated {
+ public:
+  bool operator()(char16 x, char16 y) const { return tolower(x) == tolower(y); }
+};
 
-namespace base {
+}  // namespace
 
 bool IsWprintfFormatPortable(const wchar_t* format) {
   for (const wchar_t* position = format; *position != '\0'; ++position) {
@@ -139,6 +148,53 @@
   return true;
 }
 
+template <class StringType>
+int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
+                                 BasicStringPiece<StringType> b) {
+  // Find the first characters that aren't equal and compare them.  If the end
+  // of one of the strings is found before a nonequal character, the lengths
+  // of the strings are compared.
+  size_t i = 0;
+  while (i < a.length() && i < b.length()) {
+    typename StringType::value_type lower_a = ToLowerASCII(a[i]);
+    typename StringType::value_type lower_b = ToLowerASCII(b[i]);
+    if (lower_a < lower_b)
+      return -1;
+    if (lower_a > lower_b)
+      return 1;
+    i++;
+  }
+
+  // End of one string hit before finding a different character. Expect the
+  // common case to be "strings equal" at this point so check that first.
+  if (a.length() == b.length())
+    return 0;
+
+  if (a.length() < b.length())
+    return -1;
+  return 1;
+}
+
+int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+  return CompareCaseInsensitiveASCIIT<std::string>(a, b);
+}
+
+int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+  return CompareCaseInsensitiveASCIIT<string16>(a, b);
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+  if (a.length() != b.length())
+    return false;
+  return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+  if (a.length() != b.length())
+    return false;
+  return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
+}
+
 const std::string& EmptyString() {
   return EmptyStrings::GetInstance()->s;
 }
@@ -168,54 +224,60 @@
 }
 
 bool ReplaceChars(const string16& input,
-                  const base::StringPiece16& replace_chars,
+                  const StringPiece16& replace_chars,
                   const string16& replace_with,
                   string16* output) {
   return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
 }
 
 bool ReplaceChars(const std::string& input,
-                  const base::StringPiece& replace_chars,
+                  const StringPiece& replace_chars,
                   const std::string& replace_with,
                   std::string* output) {
   return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
 }
 
 bool RemoveChars(const string16& input,
-                 const base::StringPiece16& remove_chars,
+                 const StringPiece16& remove_chars,
                  string16* output) {
   return ReplaceChars(input, remove_chars.as_string(), string16(), output);
 }
 
 bool RemoveChars(const std::string& input,
-                 const base::StringPiece& remove_chars,
+                 const StringPiece& remove_chars,
                  std::string* output) {
   return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
 }
 
-template<typename STR>
-TrimPositions TrimStringT(const STR& input,
-                          const STR& trim_chars,
+template <typename Str>
+TrimPositions TrimStringT(const Str& input,
+                          BasicStringPiece<Str> trim_chars,
                           TrimPositions positions,
-                          STR* output) {
-  // Find the edges of leading/trailing whitespace as desired.
+                          Str* output) {
+  // Find the edges of leading/trailing whitespace as desired. Need to use
+  // a StringPiece version of input to be able to call find* on it with the
+  // StringPiece version of trim_chars (normally the trim_chars will be a
+  // constant so avoid making a copy).
+  BasicStringPiece<Str> input_piece(input);
   const size_t last_char = input.length() - 1;
-  const size_t first_good_char = (positions & TRIM_LEADING) ?
-      input.find_first_not_of(trim_chars) : 0;
-  const size_t last_good_char = (positions & TRIM_TRAILING) ?
-      input.find_last_not_of(trim_chars) : last_char;
+  const size_t first_good_char = (positions & TRIM_LEADING)
+                                     ? input_piece.find_first_not_of(trim_chars)
+                                     : 0;
+  const size_t last_good_char = (positions & TRIM_TRAILING)
+                                    ? input_piece.find_last_not_of(trim_chars)
+                                    : last_char;
 
-  // When the string was all whitespace, report that we stripped off whitespace
-  // from whichever position the caller was interested in.  For empty input, we
-  // stripped no whitespace, but we still need to clear |output|.
-  if (input.empty() ||
-      (first_good_char == STR::npos) || (last_good_char == STR::npos)) {
+  // When the string was all trimmed, report that we stripped off characters
+  // from whichever position the caller was interested in. For empty input, we
+  // stripped no characters, but we still need to clear |output|.
+  if (input.empty() || (first_good_char == Str::npos) ||
+      (last_good_char == Str::npos)) {
     bool input_was_empty = input.empty();  // in case output == &input
     output->clear();
     return input_was_empty ? TRIM_NONE : positions;
   }
 
-  // Trim the whitespace.
+  // Trim.
   *output =
       input.substr(first_good_char, last_good_char - first_good_char + 1);
 
@@ -226,17 +288,39 @@
 }
 
 bool TrimString(const string16& input,
-                const base::StringPiece16& trim_chars,
+                StringPiece16 trim_chars,
                 string16* output) {
-  return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
-      TRIM_NONE;
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
 }
 
 bool TrimString(const std::string& input,
-                const base::StringPiece& trim_chars,
+                StringPiece trim_chars,
                 std::string* output) {
-  return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
-      TRIM_NONE;
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+template <typename Str>
+BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
+                                       BasicStringPiece<Str> trim_chars,
+                                       TrimPositions positions) {
+  size_t begin =
+      (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
+  size_t end = (positions & TRIM_TRAILING)
+                   ? input.find_last_not_of(trim_chars) + 1
+                   : input.size();
+  return input.substr(begin, end - begin);
+}
+
+StringPiece16 TrimString(StringPiece16 input,
+                         const StringPiece16& trim_chars,
+                         TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
+}
+
+StringPiece TrimString(StringPiece input,
+                       const StringPiece& trim_chars,
+                       TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
 }
 
 void TruncateUTF8ToByteSize(const std::string& input,
@@ -278,14 +362,22 @@
 TrimPositions TrimWhitespace(const string16& input,
                              TrimPositions positions,
                              string16* output) {
-  return TrimStringT(input, base::string16(kWhitespaceUTF16), positions,
-                     output);
+  return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
+}
+
+StringPiece16 TrimWhitespaceASCII(StringPiece16 input,
+                                  TrimPositions positions) {
+  return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
 }
 
 TrimPositions TrimWhitespaceASCII(const std::string& input,
                                   TrimPositions positions,
                                   std::string* output) {
-  return TrimStringT(input, std::string(kWhitespaceASCII), positions, output);
+  return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
+}
+
+StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
+  return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
 }
 
 // This function is only for backward-compatibility.
@@ -309,7 +401,7 @@
 
   int chars_written = 0;
   for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
-    if (IsWhitespace(*i)) {
+    if (IsUnicodeWhitespace(*i)) {
       if (!in_whitespace) {
         // Reduce all whitespace sequences to a single space.
         in_whitespace = true;
@@ -482,55 +574,123 @@
   return std::equal(b.begin(), b.end(), a.begin());
 }
 
-}  // namespace base
+template <typename Str>
+bool StartsWithT(BasicStringPiece<Str> str,
+                 BasicStringPiece<Str> search_for,
+                 CompareCase case_sensitivity) {
+  if (search_for.size() > str.size())
+    return false;
 
-bool StartsWithASCII(const std::string& str,
-                     const std::string& search,
-                     bool case_sensitive) {
-  if (case_sensitive)
-    return str.compare(0, search.length(), search) == 0;
-  else
-    return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
-}
+  BasicStringPiece<Str> source = str.substr(0, search_for.size());
 
-template <typename STR>
-bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
-  if (case_sensitive) {
-    return str.compare(0, search.length(), search) == 0;
-  } else {
-    if (search.size() > str.size())
+  switch (case_sensitivity) {
+    case CompareCase::SENSITIVE:
+      return source == search_for;
+
+    case CompareCase::INSENSITIVE_ASCII:
+      return std::equal(
+          search_for.begin(), search_for.end(), source.begin(),
+          CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+    default:
+      NOTREACHED();
       return false;
-    return std::equal(search.begin(), search.end(), str.begin(),
-                      base::CaseInsensitiveCompare<typename STR::value_type>());
   }
 }
 
-bool StartsWith(const string16& str, const string16& search,
+bool StartsWith(StringPiece str,
+                StringPiece search_for,
+                CompareCase case_sensitivity) {
+  return StartsWithT<std::string>(str, search_for, case_sensitivity);
+}
+
+bool StartsWith(StringPiece16 str,
+                StringPiece16 search_for,
+                CompareCase case_sensitivity) {
+  return StartsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+bool StartsWith(const string16& str,
+                const string16& search,
                 bool case_sensitive) {
-  return StartsWithT(str, search, case_sensitive);
+  if (!case_sensitive) {
+    // This function was originally written using the current locale functions
+    // for case-insensitive comparisons. Emulate this behavior until callers
+    // can be converted either to use the case-insensitive ASCII one (most
+    // callers) or ICU functions in base_i18n.
+    if (search.size() > str.size())
+      return false;
+    return std::equal(search.begin(), search.end(), str.begin(),
+                      CaseInsensitiveCompareDeprecated());
+  }
+  return StartsWith(StringPiece16(str), StringPiece16(search),
+                    CompareCase::SENSITIVE);
 }
 
-template <typename STR>
-bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
-  size_t str_length = str.length();
-  size_t search_length = search.length();
-  if (search_length > str_length)
+template <typename Str>
+bool EndsWithT(BasicStringPiece<Str> str,
+               BasicStringPiece<Str> search_for,
+               CompareCase case_sensitivity) {
+  if (search_for.size() > str.size())
     return false;
-  if (case_sensitive)
-    return str.compare(str_length - search_length, search_length, search) == 0;
-  return std::equal(search.begin(), search.end(),
-                    str.begin() + (str_length - search_length),
-                    base::CaseInsensitiveCompare<typename STR::value_type>());
+
+  BasicStringPiece<Str> source =
+      str.substr(str.size() - search_for.size(), search_for.size());
+
+  switch (case_sensitivity) {
+    case CompareCase::SENSITIVE:
+      return source == search_for;
+
+    case CompareCase::INSENSITIVE_ASCII:
+      return std::equal(
+          source.begin(), source.end(), search_for.begin(),
+          CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+    default:
+      NOTREACHED();
+      return false;
+  }
 }
 
-bool EndsWith(const std::string& str, const std::string& search,
-              bool case_sensitive) {
-  return EndsWithT(str, search, case_sensitive);
+bool EndsWith(StringPiece str,
+              StringPiece search_for,
+              CompareCase case_sensitivity) {
+  return EndsWithT<std::string>(str, search_for, case_sensitivity);
 }
 
-bool EndsWith(const string16& str, const string16& search,
+bool EndsWith(StringPiece16 str,
+              StringPiece16 search_for,
+              CompareCase case_sensitivity) {
+  return EndsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+bool EndsWith(const string16& str,
+              const string16& search,
               bool case_sensitive) {
-  return EndsWithT(str, search, case_sensitive);
+  if (!case_sensitive) {
+    // This function was originally written using the current locale functions
+    // for case-insensitive comparisons. Emulate this behavior until callers
+    // can be converted either to use the case-insensitive ASCII one (most
+    // callers) or ICU functions in base_i18n.
+    if (search.size() > str.size())
+      return false;
+    return std::equal(search.begin(), search.end(),
+                      str.begin() + (str.size() - search.size()),
+                      CaseInsensitiveCompareDeprecated());
+  }
+  return EndsWith(StringPiece16(str), StringPiece16(search),
+                  CompareCase::SENSITIVE);
+}
+
+char HexDigitToInt(wchar_t c) {
+  DCHECK(IsHexDigit(c));
+  if (c >= '0' && c <= '9')
+    return static_cast<char>(c - '0');
+  if (c >= 'A' && c <= 'F')
+    return static_cast<char>(c - 'A' + 10);
+  if (c >= 'a' && c <= 'f')
+    return static_cast<char>(c - 'a' + 10);
+  return 0;
 }
 
 static const char* const kByteStringsUnlocalized[] = {
@@ -561,20 +721,20 @@
                    kByteStringsUnlocalized[dimension]);
   }
 
-  return base::ASCIIToUTF16(buf);
+  return ASCIIToUTF16(buf);
 }
 
 // Runs in O(n) time in the length of |str|.
-template<class StringType>
+template <class StringType>
 void DoReplaceSubstringsAfterOffset(StringType* str,
                                     size_t offset,
-                                    const StringType& find_this,
-                                    const StringType& replace_with,
+                                    BasicStringPiece<StringType> find_this,
+                                    BasicStringPiece<StringType> replace_with,
                                     bool replace_all) {
   DCHECK(!find_this.empty());
 
   // If the find string doesn't appear, there's nothing to do.
-  offset = str->find(find_this, offset);
+  offset = str->find(find_this.data(), offset, find_this.size());
   if (offset == StringType::npos)
     return;
 
@@ -582,7 +742,7 @@
   // complicated.
   size_t find_length = find_this.length();
   if (!replace_all) {
-    str->replace(offset, find_length, replace_with);
+    str->replace(offset, find_length, replace_with.data(), replace_with.size());
     return;
   }
 
@@ -591,8 +751,10 @@
   size_t replace_length = replace_with.length();
   if (find_length == replace_length) {
     do {
-      str->replace(offset, find_length, replace_with);
-      offset = str->find(find_this, offset + replace_length);
+      str->replace(offset, find_length, replace_with.data(),
+                   replace_with.size());
+      offset = str->find(find_this.data(), offset + replace_length,
+                         find_this.size());
     } while (offset != StringType::npos);
     return;
   }
@@ -609,11 +771,14 @@
     size_t write_offset = offset;
     do {
       if (replace_length) {
-        str->replace(write_offset, replace_length, replace_with);
+        str->replace(write_offset, replace_length, replace_with.data(),
+                     replace_with.size());
         write_offset += replace_length;
       }
       size_t read_offset = offset + find_length;
-      offset = std::min(str->find(find_this, read_offset), str_length);
+      offset =
+          std::min(str->find(find_this.data(), read_offset, find_this.size()),
+                   str_length);
       size_t length = offset - read_offset;
       if (length) {
         memmove(&(*str)[write_offset], &(*str)[read_offset],
@@ -642,13 +807,15 @@
     // exit from the loop, |current_match| will point at the last instance of
     // the find string, and we won't need to find() it again immediately.
     current_match = offset;
-    offset = str->find(find_this, offset + find_length);
+    offset =
+        str->find(find_this.data(), offset + find_length, find_this.size());
   } while (offset != StringType::npos);
   str->resize(final_length);
 
   // Now do the replacement loop, working backwards through the string.
-  for (size_t prev_match = str_length, write_offset = final_length; ;
-       current_match = str->rfind(find_this, current_match - 1)) {
+  for (size_t prev_match = str_length, write_offset = final_length;;
+       current_match =
+           str->rfind(find_this.data(), current_match - 1, find_this.size())) {
     size_t read_offset = current_match + find_length;
     size_t length = prev_match - read_offset;
     if (length) {
@@ -657,7 +824,8 @@
               length * sizeof(typename StringType::value_type));
     }
     write_offset -= replace_length;
-    str->replace(write_offset, replace_length, replace_with);
+    str->replace(write_offset, replace_length, replace_with.data(),
+                 replace_with.size());
     if (current_match == first_match)
       return;
     prev_match = current_match;
@@ -666,128 +834,97 @@
 
 void ReplaceFirstSubstringAfterOffset(string16* str,
                                       size_t start_offset,
-                                      const string16& find_this,
-                                      const string16& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 false);  // replace first instance
+                                      StringPiece16 find_this,
+                                      StringPiece16 replace_with) {
+  DoReplaceSubstringsAfterOffset<string16>(
+      str, start_offset, find_this, replace_with, false);  // Replace first.
 }
 
 void ReplaceFirstSubstringAfterOffset(std::string* str,
                                       size_t start_offset,
-                                      const std::string& find_this,
-                                      const std::string& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 false);  // replace first instance
+                                      StringPiece find_this,
+                                      StringPiece replace_with) {
+  DoReplaceSubstringsAfterOffset<std::string>(
+      str, start_offset, find_this, replace_with, false);  // Replace first.
 }
 
 void ReplaceSubstringsAfterOffset(string16* str,
                                   size_t start_offset,
-                                  const string16& find_this,
-                                  const string16& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 true);  // replace all instances
+                                  StringPiece16 find_this,
+                                  StringPiece16 replace_with) {
+  DoReplaceSubstringsAfterOffset<string16>(str, start_offset, find_this,
+                                           replace_with, true);  // Replace all.
 }
 
 void ReplaceSubstringsAfterOffset(std::string* str,
                                   size_t start_offset,
-                                  const std::string& find_this,
-                                  const std::string& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 true);  // replace all instances
+                                  StringPiece find_this,
+                                  StringPiece replace_with) {
+  DoReplaceSubstringsAfterOffset<std::string>(
+      str, start_offset, find_this, replace_with, true);  // Replace all.
 }
 
-
-template<typename STR>
-static size_t TokenizeT(const STR& str,
-                        const STR& delimiters,
-                        std::vector<STR>* tokens) {
-  tokens->clear();
-
-  size_t start = str.find_first_not_of(delimiters);
-  while (start != STR::npos) {
-    size_t end = str.find_first_of(delimiters, start + 1);
-    if (end == STR::npos) {
-      tokens->push_back(str.substr(start));
-      break;
-    } else {
-      tokens->push_back(str.substr(start, end - start));
-      start = str.find_first_not_of(delimiters, end + 1);
-    }
-  }
-
-  return tokens->size();
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(string_type* str,
+                                                    size_t length_with_null) {
+  DCHECK_GT(length_with_null, 1u);
+  str->reserve(length_with_null);
+  str->resize(length_with_null - 1);
+  return &((*str)[0]);
 }
 
-size_t Tokenize(const string16& str,
-                const string16& delimiters,
-                std::vector<string16>* tokens) {
-  return TokenizeT(str, delimiters, tokens);
+char* WriteInto(std::string* str, size_t length_with_null) {
+  return WriteIntoT(str, length_with_null);
 }
 
-size_t Tokenize(const std::string& str,
-                const std::string& delimiters,
-                std::vector<std::string>* tokens) {
-  return TokenizeT(str, delimiters, tokens);
+char16* WriteInto(string16* str, size_t length_with_null) {
+  return WriteIntoT(str, length_with_null);
 }
 
-size_t Tokenize(const base::StringPiece& str,
-                const base::StringPiece& delimiters,
-                std::vector<base::StringPiece>* tokens) {
-  return TokenizeT(str, delimiters, tokens);
-}
-
-template<typename STR>
-static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
+template <typename STR>
+static STR JoinStringT(const std::vector<STR>& parts,
+                       BasicStringPiece<STR> sep) {
   if (parts.empty())
     return STR();
 
   STR result(parts[0]);
-  typename std::vector<STR>::const_iterator iter = parts.begin();
+  auto iter = parts.begin();
   ++iter;
 
   for (; iter != parts.end(); ++iter) {
-    result += sep;
+    sep.AppendToString(&result);
     result += *iter;
   }
 
   return result;
 }
 
-std::string JoinString(const std::vector<std::string>& parts, char sep) {
-  return JoinStringT(parts, std::string(1, sep));
-}
-
-string16 JoinString(const std::vector<string16>& parts, char16 sep) {
-  return JoinStringT(parts, string16(1, sep));
-}
-
 std::string JoinString(const std::vector<std::string>& parts,
-                       const std::string& separator) {
+                       StringPiece separator) {
   return JoinStringT(parts, separator);
 }
 
 string16 JoinString(const std::vector<string16>& parts,
-                    const string16& separator) {
+                    StringPiece16 separator) {
   return JoinStringT(parts, separator);
 }
 
-template<class FormatStringType, class OutStringType>
-OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
-    const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
+template <class FormatStringType, class OutStringType>
+OutStringType DoReplaceStringPlaceholders(
+    const FormatStringType& format_string,
+    const std::vector<OutStringType>& subst,
+    std::vector<size_t>* offsets) {
   size_t substitutions = subst.size();
 
   size_t sub_length = 0;
-  for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
-       iter != subst.end(); ++iter) {
-    sub_length += iter->length();
-  }
+  for (const auto& cur : subst)
+    sub_length += cur.length();
 
   OutStringType formatted;
   formatted.reserve(format_string.length() + sub_length);
 
   std::vector<ReplacementOffset> r_offsets;
-  for (typename FormatStringType::const_iterator i = format_string.begin();
-       i != format_string.end(); ++i) {
+  for (auto i = format_string.begin(); i != format_string.end(); ++i) {
     if ('$' == *i) {
       if (i + 1 != format_string.end()) {
         ++i;
@@ -825,10 +962,8 @@
     }
   }
   if (offsets) {
-    for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
-         i != r_offsets.end(); ++i) {
-      offsets->push_back(i->offset);
-    }
+    for (const auto& cur : r_offsets)
+      offsets->push_back(cur.offset);
   }
   return formatted;
 }
@@ -839,7 +974,7 @@
   return DoReplaceStringPlaceholders(format_string, subst, offsets);
 }
 
-std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
+std::string ReplaceStringPlaceholders(const StringPiece& format_string,
                                       const std::vector<std::string>& subst,
                                       std::vector<size_t>* offsets) {
   return DoReplaceStringPlaceholders(format_string, subst, offsets);
@@ -859,161 +994,6 @@
   return result;
 }
 
-static bool IsWildcard(base_icu::UChar32 character) {
-  return character == '*' || character == '?';
-}
-
-// Move the strings pointers to the point where they start to differ.
-template <typename CHAR, typename NEXT>
-static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
-                         const CHAR** string, const CHAR* string_end,
-                         NEXT next) {
-  const CHAR* escape = NULL;
-  while (*pattern != pattern_end && *string != string_end) {
-    if (!escape && IsWildcard(**pattern)) {
-      // We don't want to match wildcard here, except if it's escaped.
-      return;
-    }
-
-    // Check if the escapement char is found. If so, skip it and move to the
-    // next character.
-    if (!escape && **pattern == '\\') {
-      escape = *pattern;
-      next(pattern, pattern_end);
-      continue;
-    }
-
-    // Check if the chars match, if so, increment the ptrs.
-    const CHAR* pattern_next = *pattern;
-    const CHAR* string_next = *string;
-    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
-    if (pattern_char == next(&string_next, string_end) &&
-        pattern_char != CBU_SENTINEL) {
-      *pattern = pattern_next;
-      *string = string_next;
-    } else {
-      // Uh oh, it did not match, we are done. If the last char was an
-      // escapement, that means that it was an error to advance the ptr here,
-      // let's put it back where it was. This also mean that the MatchPattern
-      // function will return false because if we can't match an escape char
-      // here, then no one will.
-      if (escape) {
-        *pattern = escape;
-      }
-      return;
-    }
-
-    escape = NULL;
-  }
-}
-
-template <typename CHAR, typename NEXT>
-static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
-  while (*pattern != end) {
-    if (!IsWildcard(**pattern))
-      return;
-    next(pattern, end);
-  }
-}
-
-template <typename CHAR, typename NEXT>
-static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
-                          const CHAR* pattern, const CHAR* pattern_end,
-                          int depth,
-                          NEXT next) {
-  const int kMaxDepth = 16;
-  if (depth > kMaxDepth)
-    return false;
-
-  // Eat all the matching chars.
-  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
-
-  // If the string is empty, then the pattern must be empty too, or contains
-  // only wildcards.
-  if (eval == eval_end) {
-    EatWildcard(&pattern, pattern_end, next);
-    return pattern == pattern_end;
-  }
-
-  // Pattern is empty but not string, this is not a match.
-  if (pattern == pattern_end)
-    return false;
-
-  // If this is a question mark, then we need to compare the rest with
-  // the current string or the string with one character eaten.
-  const CHAR* next_pattern = pattern;
-  next(&next_pattern, pattern_end);
-  if (pattern[0] == '?') {
-    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
-                      depth + 1, next))
-      return true;
-    const CHAR* next_eval = eval;
-    next(&next_eval, eval_end);
-    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
-                      depth + 1, next))
-      return true;
-  }
-
-  // This is a *, try to match all the possible substrings with the remainder
-  // of the pattern.
-  if (pattern[0] == '*') {
-    // Collapse duplicate wild cards (********** into *) so that the
-    // method does not recurse unnecessarily. http://crbug.com/52839
-    EatWildcard(&next_pattern, pattern_end, next);
-
-    while (eval != eval_end) {
-      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
-                        depth + 1, next))
-        return true;
-      eval++;
-    }
-
-    // We reached the end of the string, let see if the pattern contains only
-    // wildcards.
-    if (eval == eval_end) {
-      EatWildcard(&pattern, pattern_end, next);
-      if (pattern != pattern_end)
-        return false;
-      return true;
-    }
-  }
-
-  return false;
-}
-
-struct NextCharUTF8 {
-  base_icu::UChar32 operator()(const char** p, const char* end) {
-    base_icu::UChar32 c;
-    int offset = 0;
-    CBU8_NEXT(*p, offset, end - *p, c);
-    *p += offset;
-    return c;
-  }
-};
-
-struct NextCharUTF16 {
-  base_icu::UChar32 operator()(const char16** p, const char16* end) {
-    base_icu::UChar32 c;
-    int offset = 0;
-    CBU16_NEXT(*p, offset, end - *p, c);
-    *p += offset;
-    return c;
-  }
-};
-
-bool MatchPattern(const base::StringPiece& eval,
-                  const base::StringPiece& pattern) {
-  return MatchPatternT(eval.data(), eval.data() + eval.size(),
-                       pattern.data(), pattern.data() + pattern.size(),
-                       0, NextCharUTF8());
-}
-
-bool MatchPattern(const string16& eval, const string16& pattern) {
-  return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
-                       pattern.c_str(), pattern.c_str() + pattern.size(),
-                       0, NextCharUTF16());
-}
-
 // The following code is compatible with the OpenBSD lcpy interface.  See:
 //   http://www.gratisoft.us/todd/papers/strlcpy.html
 //   ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
@@ -1038,9 +1018,11 @@
 
 }  // namespace
 
-size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+size_t strlcpy(char* dst, const char* src, size_t dst_size) {
   return lcpyT<char>(dst, src, dst_size);
 }
-size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
   return lcpyT<wchar_t>(dst, src, dst_size);
 }
+
+}  // namespace base
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index bea44ae..9e50a33 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -21,23 +21,10 @@
 
 namespace base {
 
-// C standard-library functions like "strncasecmp" and "snprintf" that aren't
-// cross-platform are provided as "base::strncasecmp", and their prototypes
-// are listed below.  These functions are then implemented as inline calls
-// to the platform-specific equivalents in the platform-specific headers.
-
-// Compares the two strings s1 and s2 without regard to case using
-// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
-// s2 > s1 according to a lexicographic comparison.
-int strcasecmp(const char* s1, const char* s2);
-
-// Compares up to count characters of s1 and s2 without regard to case using
-// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
-// s2 > s1 according to a lexicographic comparison.
-int strncasecmp(const char* s1, const char* s2, size_t count);
-
-// Same as strncmp but for char16 strings.
-int strncmp16(const char16* s1, const char16* s2, size_t count);
+// C standard-library functions that aren't cross-platform are provided as
+// "base::...", and their prototypes are listed below. These functions are
+// then implemented as inline calls to the platform-specific equivalents in the
+// platform-specific headers.
 
 // Wrapper for vsnprintf that always null-terminates and always returns the
 // number of characters that would be in an untruncated formatted
@@ -59,6 +46,19 @@
   return result;
 }
 
+// TODO(mark) http://crbug.com/472900 crashpad shouldn't use base while
+// being DEPSed in. This backwards-compat hack is provided until crashpad is
+// updated.
+#if defined(OS_WIN)
+inline int strcasecmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+#else  // Posix
+inline int strcasecmp(const char* string1, const char* string2) {
+  return ::strcasecmp(string1, string2);
+}
+#endif
+
 // BSD-style safe and consistent string copy functions.
 // Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
 // Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
@@ -103,17 +103,14 @@
   return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
 }
 
-// Function objects to aid in comparing/searching strings.
-
-template<typename Char> struct CaseInsensitiveCompare {
- public:
-  bool operator()(Char x, Char y) const {
-    // TODO(darin): Do we really want to do locale sensitive comparisons here?
-    // See http://crbug.com/24917
-    return tolower(x) == tolower(y);
-  }
-};
-
+// Functor for case-insensitive ASCII comparisons for STL algorithms like
+// std::search.
+//
+// Note that a full Unicode version of this functor is not possible to write
+// because case mappings might change the number of characters, depend on
+// context (combining accents), and require handling UTF-16. If you need
+// proper Unicode support, use base::i18n::ToLower/FoldCase and then just
+// use a normal operator== on the result.
 template<typename Char> struct CaseInsensitiveCompareASCII {
  public:
   bool operator()(Char x, Char y) const {
@@ -121,6 +118,22 @@
   }
 };
 
+// Like strcasecmp for case-insensitive ASCII characters only. Returns:
+//   -1  (a < b)
+//    0  (a == b)
+//    1  (a > b)
+// (unlike strcasecmp which can return values greater or less than 1/-1). For
+// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase
+// and then just call the normal string operators on the result.
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// Equality for ASCII case-insensitive comparisons. For full Unicode support,
+// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either
+// == or !=.
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
 // These threadsafe functions return references to globally unique empty
 // strings.
 //
@@ -138,10 +151,12 @@
 BASE_EXPORT const string16& EmptyString16();
 
 // Contains the set of characters representing whitespace in the corresponding
-// encoding. Null-terminated.
-BASE_EXPORT extern const wchar_t kWhitespaceWide[];
-BASE_EXPORT extern const char16 kWhitespaceUTF16[];
+// encoding. Null-terminated. The ASCII versions are the whitespaces as defined
+// by HTML5, and don't include control characters.
+BASE_EXPORT extern const wchar_t kWhitespaceWide[];  // Includes Unicode.
+BASE_EXPORT extern const char16 kWhitespaceUTF16[];  // Includes Unicode.
 BASE_EXPORT extern const char kWhitespaceASCII[];
+BASE_EXPORT extern const char16 kWhitespaceASCIIAs16[];  // No unicode.
 
 // Null-terminated string representing the UTF-8 byte order mark.
 BASE_EXPORT extern const char kUtf8ByteOrderMark[];
@@ -150,10 +165,10 @@
 // if any characters were removed.  |remove_chars| must be null-terminated.
 // NOTE: Safe to use the same variable for both |input| and |output|.
 BASE_EXPORT bool RemoveChars(const string16& input,
-                             const base::StringPiece16& remove_chars,
+                             const StringPiece16& remove_chars,
                              string16* output);
 BASE_EXPORT bool RemoveChars(const std::string& input,
-                             const base::StringPiece& remove_chars,
+                             const StringPiece& remove_chars,
                              std::string* output);
 
 // Replaces characters in |replace_chars| from anywhere in |input| with
@@ -162,49 +177,65 @@
 // |replace_chars| must be null-terminated.
 // NOTE: Safe to use the same variable for both |input| and |output|.
 BASE_EXPORT bool ReplaceChars(const string16& input,
-                              const base::StringPiece16& replace_chars,
+                              const StringPiece16& replace_chars,
                               const string16& replace_with,
                               string16* output);
 BASE_EXPORT bool ReplaceChars(const std::string& input,
-                              const base::StringPiece& replace_chars,
+                              const StringPiece& replace_chars,
                               const std::string& replace_with,
                               std::string* output);
 
+enum TrimPositions {
+  TRIM_NONE = 0,
+  TRIM_LEADING = 1 << 0,
+  TRIM_TRAILING = 1 << 1,
+  TRIM_ALL = TRIM_LEADING | TRIM_TRAILING,
+};
+
 // Removes characters in |trim_chars| from the beginning and end of |input|.
-// |trim_chars| must be null-terminated.
-// NOTE: Safe to use the same variable for both |input| and |output|.
+// The 8-bit version only works on 8-bit characters, not UTF-8.
+//
+// It is safe to use the same variable for both |input| and |output| (this is
+// the normal usage to trim in-place).
 BASE_EXPORT bool TrimString(const string16& input,
-                            const base::StringPiece16& trim_chars,
+                            StringPiece16 trim_chars,
                             string16* output);
 BASE_EXPORT bool TrimString(const std::string& input,
-                            const base::StringPiece& trim_chars,
+                            StringPiece trim_chars,
                             std::string* output);
 
+// StringPiece versions of the above. The returned pieces refer to the original
+// buffer.
+BASE_EXPORT StringPiece16 TrimString(StringPiece16 input,
+                                     const StringPiece16& trim_chars,
+                                     TrimPositions positions);
+BASE_EXPORT StringPiece TrimString(StringPiece input,
+                                   const StringPiece& trim_chars,
+                                   TrimPositions positions);
+
 // Truncates a string to the nearest UTF-8 character that will leave
 // the string less than or equal to the specified byte size.
 BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
                                         const size_t byte_size,
                                         std::string* output);
 
-// Trims any whitespace from either end of the input string.  Returns where
-// whitespace was found.
-// The non-wide version has two functions:
-// * TrimWhitespaceASCII()
-//   This function is for ASCII strings and only looks for ASCII whitespace;
-// Please choose the best one according to your usage.
+// Trims any whitespace from either end of the input string.
+//
+// The StringPiece versions return a substring referencing the input buffer.
+// The ASCII versions look only for ASCII whitespace.
+//
+// The std::string versions return where whitespace was found.
 // NOTE: Safe to use the same variable for both input and output.
-enum TrimPositions {
-  TRIM_NONE     = 0,
-  TRIM_LEADING  = 1 << 0,
-  TRIM_TRAILING = 1 << 1,
-  TRIM_ALL      = TRIM_LEADING | TRIM_TRAILING,
-};
 BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
                                          TrimPositions positions,
-                                         base::string16* output);
+                                         string16* output);
+BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
+                                         TrimPositions positions);
 BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
                                               TrimPositions positions,
                                               std::string* output);
+BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
+                                            TrimPositions positions);
 
 // Deprecated. This function is only for backward compatibility and calls
 // TrimWhitespaceASCII().
@@ -315,32 +346,41 @@
 // strings are not ASCII.
 BASE_EXPORT bool EqualsASCII(const string16& a, const StringPiece& b);
 
-}  // namespace base
+// Indicates case sensitivity of comparisons. Only ASCII case insensitivity
+// is supported. Full Unicode case-insensitive conversions would need to go in
+// base/i18n so it can use ICU.
+//
+// If you need to do Unicode-aware case-insensitive StartsWith/EndsWith, it's
+// best to call base::i18n::ToLower() or base::i18n::FoldCase() (see
+// base/i18n/case_conversion.h for usage advice) on the arguments, and then use
+// the results to a case-sensitive comparison.
+enum class CompareCase {
+  SENSITIVE,
+  INSENSITIVE_ASCII,
+};
 
-#if defined(OS_WIN)
-#include "base/strings/string_util_win.h"
-#elif defined(OS_POSIX)
-#include "base/strings/string_util_posix.h"
-#else
-#error Define string operations appropriately for your platform
-#endif
+BASE_EXPORT bool StartsWith(StringPiece str,
+                            StringPiece search_for,
+                            CompareCase case_sensitivity);
+BASE_EXPORT bool StartsWith(StringPiece16 str,
+                            StringPiece16 search_for,
+                            CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece str,
+                          StringPiece search_for,
+                          CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece16 str,
+                          StringPiece16 search_for,
+                          CompareCase case_sensitivity);
 
-// Returns true if str starts with search, or false otherwise.
-BASE_EXPORT bool StartsWithASCII(const std::string& str,
-                                 const std::string& search,
-                                 bool case_sensitive);
-BASE_EXPORT bool StartsWith(const base::string16& str,
-                            const base::string16& search,
-                            bool case_sensitive);
-
-// Returns true if str ends with search, or false otherwise.
-BASE_EXPORT bool EndsWith(const std::string& str,
-                          const std::string& search,
-                          bool case_sensitive);
-BASE_EXPORT bool EndsWith(const base::string16& str,
-                          const base::string16& search,
-                          bool case_sensitive);
-
+// DEPRECATED. Returns true if str starts/ends with search, or false otherwise.
+// TODO(brettw) remove in favor of the "enum" versions above.
+inline bool StartsWithASCII(const std::string& str,
+                            const std::string& search,
+                            bool case_sensitive) {
+  return StartsWith(
+      StringPiece(str), StringPiece(search),
+      case_sensitive ? CompareCase::SENSITIVE : CompareCase::INSENSITIVE_ASCII);
+}
 
 // Determines the type of ASCII character, independent of locale (the C
 // library versions will change based on locale).
@@ -364,20 +404,15 @@
          (c >= 'a' && c <= 'f');
 }
 
-template <typename Char>
-inline char HexDigitToInt(Char c) {
-  DCHECK(IsHexDigit(c));
-  if (c >= '0' && c <= '9')
-    return static_cast<char>(c - '0');
-  if (c >= 'A' && c <= 'F')
-    return static_cast<char>(c - 'A' + 10);
-  if (c >= 'a' && c <= 'f')
-    return static_cast<char>(c - 'a' + 10);
-  return 0;
-}
+// Returns the integer corresponding to the given hex character. For example:
+//    '4' -> 4
+//    'a' -> 10
+//    'B' -> 11
+// Assumes the input is a valid hex character. DCHECKs in debug builds if not.
+BASE_EXPORT char HexDigitToInt(wchar_t c);
 
-// Returns true if it's a whitespace character.
-inline bool IsWhitespace(wchar_t c) {
+// Returns true if it's a Unicode whitespace character.
+inline bool IsUnicodeWhitespace(wchar_t c) {
   return wcschr(base::kWhitespaceWide, c) != NULL;
 }
 
@@ -385,20 +420,18 @@
 // appropriate for use in any UI; use of FormatBytes and friends in ui/base is
 // highly recommended instead. TODO(avi): Figure out how to get callers to use
 // FormatBytes instead; remove this.
-BASE_EXPORT base::string16 FormatBytesUnlocalized(int64 bytes);
+BASE_EXPORT string16 FormatBytesUnlocalized(int64 bytes);
 
 // Starting at |start_offset| (usually 0), replace the first instance of
 // |find_this| with |replace_with|.
-BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
-    base::string16* str,
-    size_t start_offset,
-    const base::string16& find_this,
-    const base::string16& replace_with);
-BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
-    std::string* str,
-    size_t start_offset,
-    const std::string& find_this,
-    const std::string& replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(base::string16* str,
+                                                  size_t start_offset,
+                                                  StringPiece16 find_this,
+                                                  StringPiece16 replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(std::string* str,
+                                                  size_t start_offset,
+                                                  StringPiece find_this,
+                                                  StringPiece replace_with);
 
 // Starting at |start_offset| (usually 0), look through |str| and replace all
 // instances of |find_this| with |replace_with|.
@@ -406,15 +439,14 @@
 // This does entire substrings; use std::replace in <algorithm> for single
 // characters, for example:
 //   std::replace(str.begin(), str.end(), 'a', 'b');
-BASE_EXPORT void ReplaceSubstringsAfterOffset(
-    base::string16* str,
-    size_t start_offset,
-    const base::string16& find_this,
-    const base::string16& replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(string16* str,
+                                              size_t start_offset,
+                                              StringPiece16 find_this,
+                                              StringPiece16 replace_with);
 BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
                                               size_t start_offset,
-                                              const std::string& find_this,
-                                              const std::string& replace_with);
+                                              StringPiece find_this,
+                                              StringPiece replace_with);
 
 // Reserves enough memory in |str| to accommodate |length_with_null| characters,
 // sets the size of |str| to |length_with_null - 1| characters, and returns a
@@ -436,72 +468,45 @@
 // of the string, and not doing that will mean people who access |str| rather
 // than str.c_str() will get back a string of whatever size |str| had on entry
 // to this function (probably 0).
-template <class string_type>
-inline typename string_type::value_type* WriteInto(string_type* str,
-                                                   size_t length_with_null) {
-  DCHECK_GT(length_with_null, 1u);
-  str->reserve(length_with_null);
-  str->resize(length_with_null - 1);
-  return &((*str)[0]);
-}
-
-//-----------------------------------------------------------------------------
-
-// Splits a string into its fields delimited by any of the characters in
-// |delimiters|.  Each field is added to the |tokens| vector.  Returns the
-// number of tokens found.
-BASE_EXPORT size_t Tokenize(const base::string16& str,
-                            const base::string16& delimiters,
-                            std::vector<base::string16>* tokens);
-BASE_EXPORT size_t Tokenize(const std::string& str,
-                            const std::string& delimiters,
-                            std::vector<std::string>* tokens);
-BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
-                            const base::StringPiece& delimiters,
-                            std::vector<base::StringPiece>* tokens);
+BASE_EXPORT char* WriteInto(std::string* str, size_t length_with_null);
+BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
+#ifndef OS_WIN
+BASE_EXPORT wchar_t* WriteInto(std::wstring* str, size_t length_with_null);
+#endif
 
 // Does the opposite of SplitString().
-BASE_EXPORT base::string16 JoinString(const std::vector<base::string16>& parts,
-                                      base::char16 s);
-BASE_EXPORT std::string JoinString(
-    const std::vector<std::string>& parts, char s);
-
-// Join |parts| using |separator|.
-BASE_EXPORT std::string JoinString(
-    const std::vector<std::string>& parts,
-    const std::string& separator);
-BASE_EXPORT base::string16 JoinString(
-    const std::vector<base::string16>& parts,
-    const base::string16& separator);
+BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
+                                   StringPiece separator);
+BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
+                                StringPiece16 separator);
 
 // Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
 // Additionally, any number of consecutive '$' characters is replaced by that
 // number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
 // NULL. This only allows you to use up to nine replacements.
-BASE_EXPORT base::string16 ReplaceStringPlaceholders(
-    const base::string16& format_string,
-    const std::vector<base::string16>& subst,
-    std::vector<size_t>* offsets);
+BASE_EXPORT string16
+ReplaceStringPlaceholders(const string16& format_string,
+                          const std::vector<string16>& subst,
+                          std::vector<size_t>* offsets);
 
 BASE_EXPORT std::string ReplaceStringPlaceholders(
-    const base::StringPiece& format_string,
+    const StringPiece& format_string,
     const std::vector<std::string>& subst,
     std::vector<size_t>* offsets);
 
 // Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
-BASE_EXPORT base::string16 ReplaceStringPlaceholders(
-    const base::string16& format_string,
-    const base::string16& a,
-    size_t* offset);
+BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
+                                               const string16& a,
+                                               size_t* offset);
 
-// Returns true if the string passed in matches the pattern. The pattern
-// string can contain wildcards like * and ?
-// The backslash character (\) is an escape character for * and ?
-// We limit the patterns to having a max of 16 * or ? characters.
-// ? matches 0 or 1 character, while * matches 0 or more characters.
-BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
-                              const base::StringPiece& pattern);
-BASE_EXPORT bool MatchPattern(const base::string16& string,
-                              const base::string16& pattern);
+}  // namespace base
+
+#if defined(OS_WIN)
+#include "base/strings/string_util_win.h"
+#elif defined(OS_POSIX)
+#include "base/strings/string_util_posix.h"
+#else
+#error Define string operations appropriately for your platform
+#endif
 
 #endif  // BASE_STRINGS_STRING_UTIL_H_
diff --git a/base/strings/string_util_constants.cc b/base/strings/string_util_constants.cc
index 146e5fd..d443daa 100644
--- a/base/strings/string_util_constants.cc
+++ b/base/strings/string_util_constants.cc
@@ -52,6 +52,14 @@
   0
 };
 
+const char16 kWhitespaceASCIIAs16[] = {0x09,  // CHARACTER TABULATION
+                                       0x0A,  // LINE FEED (LF)
+                                       0x0B,  // LINE TABULATION
+                                       0x0C,  // FORM FEED (FF)
+                                       0x0D,  // CARRIAGE RETURN (CR)
+                                       0x20,  // SPACE
+                                       0};
+
 const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
 
 }  // namespace base
diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h
index f4009d4..9e96697 100644
--- a/base/strings/string_util_posix.h
+++ b/base/strings/string_util_posix.h
@@ -20,27 +20,11 @@
   return ::strdup(str);
 }
 
-inline int strcasecmp(const char* string1, const char* string2) {
-  return ::strcasecmp(string1, string2);
-}
-
-inline int strncasecmp(const char* string1, const char* string2, size_t count) {
-  return ::strncasecmp(string1, string2, count);
-}
-
 inline int vsnprintf(char* buffer, size_t size,
                      const char* format, va_list arguments) {
   return ::vsnprintf(buffer, size, format, arguments);
 }
 
-inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
-#if defined(WCHAR_T_IS_UTF16)
-  return ::wcsncmp(s1, s2, count);
-#elif defined(WCHAR_T_IS_UTF32)
-  return c16memcmp(s1, s2, count);
-#endif
-}
-
 inline int vswprintf(wchar_t* buffer, size_t size,
                      const wchar_t* format, va_list arguments) {
   DCHECK(IsWprintfFormatPortable(format));
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index fb0bead..75fc58a 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -669,128 +669,7 @@
   EXPECT_EQ(15, HexDigitToInt('f'));
 }
 
-// Test for Tokenize
-template <typename STR>
-void TokenizeTest() {
-  std::vector<STR> r;
-  size_t size;
-
-  size = Tokenize(STR("This is a string"), STR(" "), &r);
-  EXPECT_EQ(4U, size);
-  ASSERT_EQ(4U, r.size());
-  EXPECT_EQ(r[0], STR("This"));
-  EXPECT_EQ(r[1], STR("is"));
-  EXPECT_EQ(r[2], STR("a"));
-  EXPECT_EQ(r[3], STR("string"));
-  r.clear();
-
-  size = Tokenize(STR("one,two,three"), STR(","), &r);
-  EXPECT_EQ(3U, size);
-  ASSERT_EQ(3U, r.size());
-  EXPECT_EQ(r[0], STR("one"));
-  EXPECT_EQ(r[1], STR("two"));
-  EXPECT_EQ(r[2], STR("three"));
-  r.clear();
-
-  size = Tokenize(STR("one,two:three;four"), STR(",:"), &r);
-  EXPECT_EQ(3U, size);
-  ASSERT_EQ(3U, r.size());
-  EXPECT_EQ(r[0], STR("one"));
-  EXPECT_EQ(r[1], STR("two"));
-  EXPECT_EQ(r[2], STR("three;four"));
-  r.clear();
-
-  size = Tokenize(STR("one,two:three;four"), STR(";,:"), &r);
-  EXPECT_EQ(4U, size);
-  ASSERT_EQ(4U, r.size());
-  EXPECT_EQ(r[0], STR("one"));
-  EXPECT_EQ(r[1], STR("two"));
-  EXPECT_EQ(r[2], STR("three"));
-  EXPECT_EQ(r[3], STR("four"));
-  r.clear();
-
-  size = Tokenize(STR("one, two, three"), STR(","), &r);
-  EXPECT_EQ(3U, size);
-  ASSERT_EQ(3U, r.size());
-  EXPECT_EQ(r[0], STR("one"));
-  EXPECT_EQ(r[1], STR(" two"));
-  EXPECT_EQ(r[2], STR(" three"));
-  r.clear();
-
-  size = Tokenize(STR("one, two, three, "), STR(","), &r);
-  EXPECT_EQ(4U, size);
-  ASSERT_EQ(4U, r.size());
-  EXPECT_EQ(r[0], STR("one"));
-  EXPECT_EQ(r[1], STR(" two"));
-  EXPECT_EQ(r[2], STR(" three"));
-  EXPECT_EQ(r[3], STR(" "));
-  r.clear();
-
-  size = Tokenize(STR("one, two, three,"), STR(","), &r);
-  EXPECT_EQ(3U, size);
-  ASSERT_EQ(3U, r.size());
-  EXPECT_EQ(r[0], STR("one"));
-  EXPECT_EQ(r[1], STR(" two"));
-  EXPECT_EQ(r[2], STR(" three"));
-  r.clear();
-
-  size = Tokenize(STR(), STR(","), &r);
-  EXPECT_EQ(0U, size);
-  ASSERT_EQ(0U, r.size());
-  r.clear();
-
-  size = Tokenize(STR(","), STR(","), &r);
-  EXPECT_EQ(0U, size);
-  ASSERT_EQ(0U, r.size());
-  r.clear();
-
-  size = Tokenize(STR(",;:."), STR(".:;,"), &r);
-  EXPECT_EQ(0U, size);
-  ASSERT_EQ(0U, r.size());
-  r.clear();
-
-  size = Tokenize(STR("\t\ta\t"), STR("\t"), &r);
-  EXPECT_EQ(1U, size);
-  ASSERT_EQ(1U, r.size());
-  EXPECT_EQ(r[0], STR("a"));
-  r.clear();
-
-  size = Tokenize(STR("\ta\t\nb\tcc"), STR("\n"), &r);
-  EXPECT_EQ(2U, size);
-  ASSERT_EQ(2U, r.size());
-  EXPECT_EQ(r[0], STR("\ta\t"));
-  EXPECT_EQ(r[1], STR("b\tcc"));
-  r.clear();
-}
-
-TEST(StringUtilTest, TokenizeStdString) {
-  TokenizeTest<std::string>();
-}
-
-TEST(StringUtilTest, TokenizeStringPiece) {
-  TokenizeTest<StringPiece>();
-}
-
-// Test for JoinString
 TEST(StringUtilTest, JoinString) {
-  std::vector<std::string> in;
-  EXPECT_EQ("", JoinString(in, ','));
-
-  in.push_back("a");
-  EXPECT_EQ("a", JoinString(in, ','));
-
-  in.push_back("b");
-  in.push_back("c");
-  EXPECT_EQ("a,b,c", JoinString(in, ','));
-
-  in.push_back(std::string());
-  EXPECT_EQ("a,b,c,", JoinString(in, ','));
-  in.push_back(" ");
-  EXPECT_EQ("a|b|c|| ", JoinString(in, '|'));
-}
-
-// Test for JoinString overloaded with std::string separator
-TEST(StringUtilTest, JoinStringWithString) {
   std::string separator(", ");
   std::vector<std::string> parts;
   EXPECT_EQ(std::string(), JoinString(parts, separator));
@@ -808,8 +687,7 @@
   EXPECT_EQ("a|b|c|| ", JoinString(parts, "|"));
 }
 
-// Test for JoinString overloaded with string16 separator
-TEST(StringUtilTest, JoinStringWithString16) {
+TEST(StringUtilTest, JoinString16) {
   string16 separator = ASCIIToUTF16(", ");
   std::vector<string16> parts;
   EXPECT_EQ(string16(), JoinString(parts, separator));
@@ -828,59 +706,83 @@
 }
 
 TEST(StringUtilTest, StartsWith) {
-  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", true));
-  EXPECT_FALSE(StartsWithASCII("JavaScript:url", "javascript", true));
-  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", false));
-  EXPECT_TRUE(StartsWithASCII("JavaScript:url", "javascript", false));
-  EXPECT_FALSE(StartsWithASCII("java", "javascript", true));
-  EXPECT_FALSE(StartsWithASCII("java", "javascript", false));
-  EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", false));
-  EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", true));
-  EXPECT_TRUE(StartsWithASCII("java", std::string(), false));
-  EXPECT_TRUE(StartsWithASCII("java", std::string(), true));
+  EXPECT_TRUE(
+      StartsWith("javascript:url", "javascript", base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(
+      StartsWith("JavaScript:url", "javascript", base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith("javascript:url", "javascript",
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith("JavaScript:url", "javascript",
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith("java", "javascript", base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(
+      StartsWith("java", "javascript", base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(std::string(), "javascript",
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(
+      StartsWith(std::string(), "javascript", base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(
+      StartsWith("java", std::string(), base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith("java", std::string(), base::CompareCase::SENSITIVE));
 
   EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
-                         ASCIIToUTF16("javascript"), true));
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::SENSITIVE));
   EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"),
-                          ASCIIToUTF16("javascript"), true));
+                          ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
   EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
-                         ASCIIToUTF16("javascript"), false));
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::INSENSITIVE_ASCII));
   EXPECT_TRUE(StartsWith(ASCIIToUTF16("JavaScript:url"),
-                         ASCIIToUTF16("javascript"), false));
-  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
-                          ASCIIToUTF16("javascript"), true));
-  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
-                          ASCIIToUTF16("javascript"), false));
-  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), false));
-  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), true));
-  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), false));
-  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), true));
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+                         base::CompareCase::SENSITIVE));
 }
 
 TEST(StringUtilTest, EndsWith) {
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
-                       ASCIIToUTF16(".plugin"), true));
-  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
-                        ASCIIToUTF16(".plugin"), true));
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
-                       ASCIIToUTF16(".plugin"), false));
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
-                       ASCIIToUTF16(".plugin"), false));
-  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), true));
-  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), false));
-  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
-                        ASCIIToUTF16(".plugin"), true));
-  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
-                        ASCIIToUTF16(".plugin"), false));
-  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), false));
-  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), true));
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), false));
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), true));
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"),
-                       ASCIIToUTF16(".plugin"), false));
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"), true));
-  EXPECT_TRUE(EndsWith(string16(), string16(), false));
-  EXPECT_TRUE(EndsWith(string16(), string16(), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(
+      EndsWith(string16(), string16(), base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(string16(), string16(), base::CompareCase::SENSITIVE));
 }
 
 TEST(StringUtilTest, GetStringFWithOffsets) {
@@ -994,45 +896,6 @@
             "$1 $$2 $$$3");
 }
 
-TEST(StringUtilTest, MatchPatternTest) {
-  EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
-  EXPECT_TRUE(MatchPattern("www.google.com", "*"));
-  EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
-  EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
-  EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
-  EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
-  EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
-  EXPECT_FALSE(MatchPattern("", "*.*"));
-  EXPECT_TRUE(MatchPattern("", "*"));
-  EXPECT_TRUE(MatchPattern("", "?"));
-  EXPECT_TRUE(MatchPattern("", ""));
-  EXPECT_FALSE(MatchPattern("Hello", ""));
-  EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
-  // Stop after a certain recursion depth.
-  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
-
-  // Test UTF8 matching.
-  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
-  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
-  EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
-  // Invalid sequences should be handled as a single invalid character.
-  EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
-  // If the pattern has invalid characters, it shouldn't match anything.
-  EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
-
-  // Test UTF16 character matching.
-  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"),
-                           UTF8ToUTF16("*.com")));
-  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
-                           UTF8ToUTF16("He??o\\*1*")));
-
-  // This test verifies that consecutive wild cards are collapsed into 1
-  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
-  // recursion depth).
-  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
-                           UTF8ToUTF16("He********************************o")));
-}
-
 TEST(StringUtilTest, LcpyTest) {
   // Test the normal case where we fit in our buffer.
   {
@@ -1197,6 +1060,26 @@
                                   kWhitespaceUTF16));
 }
 
+TEST(StringUtilTest, CompareCaseInsensitiveASCII) {
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("", ""));
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("Asdf", "aSDf"));
+
+  // Differing lengths.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("Asdf", "aSDfA"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("AsdfA", "aSDf"));
+
+  // Differing values.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA"));
+}
+
+TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("", ""));
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("Asdf", "aSDF"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", "aSDF"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz"));
+}
+
 class WriteIntoTest : public testing::Test {
  protected:
   static void WritesCorrectly(size_t num_chars) {
diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h
index 61eda20..839a799 100644
--- a/base/strings/string_util_win.h
+++ b/base/strings/string_util_win.h
@@ -20,18 +20,6 @@
   return _strdup(str);
 }
 
-inline int strcasecmp(const char* s1, const char* s2) {
-  return _stricmp(s1, s2);
-}
-
-inline int strncasecmp(const char* s1, const char* s2, size_t count) {
-  return _strnicmp(s1, s2, count);
-}
-
-inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
-  return ::wcsncmp(s1, s2, count);
-}
-
 inline int vsnprintf(char* buffer, size_t size,
                      const char* format, va_list arguments) {
   int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
index a7b12ff..6abcfc0 100644
--- a/base/strings/utf_string_conversions_unittest.cc
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -185,25 +185,22 @@
 #endif  // defined(WCHAR_T_IS_UTF32)
 
 TEST(UTFStringConversionsTest, ConvertMultiString) {
-  static wchar_t wmulti[] = {
-    L'f', L'o', L'o', L'\0',
-    L'b', L'a', L'r', L'\0',
-    L'b', L'a', L'z', L'\0',
-    L'\0'
-  };
+  static char16 multi16[] = {'f',  'o', 'o', '\0', 'b',  'a', 'r',
+                             '\0', 'b', 'a', 'z',  '\0', '\0'};
   static char multi[] = {
     'f', 'o', 'o', '\0',
     'b', 'a', 'r', '\0',
     'b', 'a', 'z', '\0',
     '\0'
   };
-  std::wstring wmultistring;
-  memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti));
-  EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length());
+  string16 multistring16;
+  memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
+         sizeof(multi16));
+  EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
   std::string expected;
   memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
   EXPECT_EQ(arraysize(multi) - 1, expected.length());
-  const std::string& converted = WideToUTF8(wmultistring);
+  const std::string& converted = UTF16ToUTF8(multistring16);
   EXPECT_EQ(arraysize(multi) - 1, converted.length());
   EXPECT_EQ(expected, converted);
 }
diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc
index 5f165c8..470e564 100644
--- a/base/synchronization/condition_variable_win.cc
+++ b/base/synchronization/condition_variable_win.cc
@@ -205,10 +205,10 @@
 };
 
 WinXPCondVar::WinXPCondVar(Lock* user_lock)
-    : user_lock_(*user_lock),
-      run_state_(RUNNING),
-      allocation_counter_(0),
-      recycling_list_size_(0) {
+    : run_state_(RUNNING),
+      user_lock_(*user_lock),
+      recycling_list_size_(0),
+      allocation_counter_(0) {
   DCHECK(user_lock);
 }
 
diff --git a/base/sys_info.cc b/base/sys_info.cc
index 8640dc1..f24ebd3 100644
--- a/base/sys_info.cc
+++ b/base/sys_info.cc
@@ -41,14 +41,14 @@
 
   // Low End Device Mode will be enabled if this client is assigned to
   // one of those EnabledXXX groups.
-  if (StartsWithASCII(group_name, "Enabled", true))
+  if (StartsWith(group_name, "Enabled", CompareCase::SENSITIVE))
     return true;
 
   return g_lazy_low_end_device.Get().value();
 }
 #endif
 
-#if !defined(OS_MACOSX) || defined(OS_IOS)
+#if (!defined(OS_MACOSX) || defined(OS_IOS)) && !defined(OS_ANDROID)
 std::string SysInfo::HardwareModelName() {
   return std::string();
 }
diff --git a/base/sys_info.h b/base/sys_info.h
index 654d694..5a81dc1 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -52,9 +52,9 @@
   static int64 Uptime();
 
   // Returns a descriptive string for the current machine model or an empty
-  // string if machime model is unknown or an error occured.
-  // e.g. MacPro1,1 on Mac.
-  // Only implemented on OS X, will return an empty string on other platforms.
+  // string if the machine model is unknown or an error occured.
+  // e.g. "MacPro1,1" on Mac, or "Nexus 5" on Android. Only implemented on OS X,
+  // Android, and Chrome OS. This returns an empty string on other platforms.
   static std::string HardwareModelName();
 
   // Returns the name of the host operating system.
@@ -129,9 +129,6 @@
   // Returns the Android build ID.
   static std::string GetAndroidBuildID();
 
-  // Returns the device's name.
-  static std::string GetDeviceName();
-
   static int DalvikHeapSizeMB();
   static int DalvikHeapGrowthLimitMB();
 #endif  // defined(OS_ANDROID)
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
index 245097f..c288ae2 100644
--- a/base/sys_info_android.cc
+++ b/base/sys_info_android.cc
@@ -155,28 +155,16 @@
 
 namespace base {
 
-std::string SysInfo::OperatingSystemName() {
-  return "Android";
-}
-
-std::string SysInfo::GetAndroidBuildCodename() {
-  char os_version_codename_str[PROP_VALUE_MAX];
-  __system_property_get("ro.build.version.codename", os_version_codename_str);
-  return std::string(os_version_codename_str);
-}
-
-std::string SysInfo::GetAndroidBuildID() {
-  char os_build_id_str[PROP_VALUE_MAX];
-  __system_property_get("ro.build.id", os_build_id_str);
-  return std::string(os_build_id_str);
-}
-
-std::string SysInfo::GetDeviceName() {
+std::string SysInfo::HardwareModelName() {
   char device_model_str[PROP_VALUE_MAX];
   __system_property_get("ro.product.model", device_model_str);
   return std::string(device_model_str);
 }
 
+std::string SysInfo::OperatingSystemName() {
+  return "Android";
+}
+
 std::string SysInfo::OperatingSystemVersion() {
   int32 major, minor, bugfix;
   OperatingSystemVersionNumbers(&major, &minor, &bugfix);
@@ -195,6 +183,18 @@
                         bugfix_version);
 }
 
+std::string SysInfo::GetAndroidBuildCodename() {
+  char os_version_codename_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.codename", os_version_codename_str);
+  return std::string(os_version_codename_str);
+}
+
+std::string SysInfo::GetAndroidBuildID() {
+  char os_build_id_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.id", os_build_id_str);
+  return std::string(os_build_id_str);
+}
+
 int SysInfo::DalvikHeapSizeMB() {
   static int heap_size = GetDalvikHeapSizeMB();
   return heap_size;
diff --git a/base/task_runner.h b/base/task_runner.h
index 7d07b8c..6369c4f 100644
--- a/base/task_runner.h
+++ b/base/task_runner.h
@@ -104,7 +104,7 @@
   //  public:
   //    void GetData() {
   //      scoped_refptr<DataBuffer> buffer = new DataBuffer();
-  //      target_thread_.message_loop_proxy()->PostTaskAndReply(
+  //      target_thread_.task_runner()->PostTaskAndReply(
   //          FROM_HERE,
   //          base::Bind(&DataBuffer::AddData, buffer),
   //          base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
index b6dd0f3..da088db 100644
--- a/base/task_runner_util.h
+++ b/base/task_runner_util.h
@@ -47,7 +47,7 @@
 // PostTaskAndReplyWithResult as in this example:
 //
 // PostTaskAndReplyWithResult(
-//     target_thread_.message_loop_proxy(),
+//     target_thread_.task_runner(),
 //     FROM_HERE,
 //     Bind(&DoWorkAndReturn),
 //     Bind(&Callback));
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index a8ae0cf..db0fc91 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -128,18 +128,24 @@
     "values_test_util.h",
   ]
 
+  data = [
+    # The isolate needs this script for setting up the test. It's not actually
+    # needed to run this target locally.
+    "//testing/test_env.py",
+  ]
+
   public_deps = [
     ":test_config",
     "//base",
-    "//base:i18n",
     "//base:base_static",
+    "//base:i18n",
   ]
   deps = [
     "//base/third_party/dynamic_annotations",
     "//testing/gmock",
     "//testing/gtest",
-    "//third_party/libxml",
     "//third_party/icu:icuuc",
+    "//third_party/libxml",
   ]
 
   if (!is_posix) {
diff --git a/base/test/android/java/src/org/chromium/base/TestUiThread.java b/base/test/android/java/src/org/chromium/base/TestUiThread.java
index 77f9660..4abec80 100644
--- a/base/test/android/java/src/org/chromium/base/TestUiThread.java
+++ b/base/test/android/java/src/org/chromium/base/TestUiThread.java
@@ -19,7 +19,7 @@
 @ThreadSafe
 public class TestUiThread {
     private static final AtomicBoolean sStarted = new AtomicBoolean(false);
-    private static final String TAG = Log.makeTag("TestUiThread");
+    private static final String TAG = "cr.TestUiThread";
 
     @CalledByNative
     private static void loop() {
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
index 53dee4a..4c7f3b8 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
@@ -10,17 +10,8 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import org.chromium.base.BaseChromiumApplication;
-import org.chromium.base.CommandLine;
 import org.chromium.base.test.util.CommandLineFlags;
 
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 /**
  * Base class for all Activity-based Instrumentation tests.
  *
@@ -43,26 +34,10 @@
         super(activityClass);
     }
 
-    /**
-     * Sets up the CommandLine with the appropriate flags.
-     *
-     * This will add the difference of the sets of flags specified by {@link CommandLineFlags.Add}
-     * and {@link CommandLineFlags.Remove} to the {@link org.chromium.base.CommandLine}. Note that
-     * trying to remove a flag set externally, i.e. by the command-line flags file, will not work.
-     */
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-
-        CommandLine.reset();
-        Context targetContext = getTargetContext();
-        assertNotNull("Unable to get a non-null target context.", targetContext);
-
-        BaseChromiumApplication.initCommandLine(targetContext);
-        Set<String> flags = getFlags(getClass().getMethod(getName()));
-        for (String flag : flags) {
-            CommandLine.getInstance().appendSwitch(flag);
-        }
+        CommandLineFlags.setUp(getTargetContext(), getClass().getMethod(getName()));
     }
 
     /**
@@ -88,31 +63,4 @@
         }
         return targetContext;
     }
-
-    private static Set<String> getFlags(AnnotatedElement element) {
-        AnnotatedElement parent = (element instanceof Method)
-                ? ((Method) element).getDeclaringClass()
-                : ((Class) element).getSuperclass();
-        Set<String> flags = (parent == null) ? new HashSet<String>() : getFlags(parent);
-
-        if (element.isAnnotationPresent(CommandLineFlags.Add.class)) {
-            flags.addAll(
-                    Arrays.asList(element.getAnnotation(CommandLineFlags.Add.class).value()));
-        }
-
-        if (element.isAnnotationPresent(CommandLineFlags.Remove.class)) {
-            List<String> flagsToRemove =
-                    Arrays.asList(element.getAnnotation(CommandLineFlags.Remove.class).value());
-            for (String flagToRemove : flagsToRemove) {
-                // If your test fails here, you have tried to remove a command-line flag via
-                // CommandLineFlags.Remove that was loaded into CommandLine via something other
-                // than CommandLineFlags.Add (probably the command-line flag file).
-                assertFalse("Unable to remove command-line flag \"" + flagToRemove + "\".",
-                        CommandLine.getInstance().hasSwitch(flagToRemove));
-            }
-            flags.removeAll(flagsToRemove);
-        }
-
-        return flags;
-    }
 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
index 8a3395a..c90ebf2 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -94,7 +94,7 @@
             @Override
             protected TestResult createTestResult() {
                 SkippingTestResult r = new SkippingTestResult();
-                r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+                addSkipChecks(r);
                 return r;
             }
         };
@@ -103,6 +103,13 @@
     }
 
     /**
+     * Adds the desired SkipChecks to result. Subclasses can add additional SkipChecks.
+     */
+    protected void addSkipChecks(SkippingTestResult result) {
+        result.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+    }
+
+    /**
      * Checks the device's SDK level against any specified minimum requirement.
      */
     public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
index 2feb83d..4dde9e5 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
@@ -4,11 +4,24 @@
 
 package org.chromium.base.test.util;
 
+import android.content.Context;
+
+import junit.framework.Assert;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.CommandLine;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * Provides annotations related to command-line flag handling.
@@ -44,5 +57,48 @@
         String[] value();
     }
 
+    /**
+     * Sets up the CommandLine with the appropriate flags.
+     *
+     * This will add the difference of the sets of flags specified by {@link CommandLineFlags.Add}
+     * and {@link CommandLineFlags.Remove} to the {@link org.chromium.base.CommandLine}. Note that
+     * trying to remove a flag set externally, i.e. by the command-line flags file, will not work.
+     */
+    public static void setUp(Context targetContext, AnnotatedElement element) {
+        Assert.assertNotNull("Unable to get a non-null target context.", targetContext);
+        CommandLine.reset();
+        BaseChromiumApplication.initCommandLine(targetContext);
+        Set<String> flags = getFlags(element);
+        for (String flag : flags) {
+            CommandLine.getInstance().appendSwitch(flag);
+        }
+    }
+
+    private static Set<String> getFlags(AnnotatedElement element) {
+        AnnotatedElement parent = (element instanceof Method)
+                ? ((Method) element).getDeclaringClass()
+                : ((Class) element).getSuperclass();
+        Set<String> flags = (parent == null) ? new HashSet<String>() : getFlags(parent);
+
+        if (element.isAnnotationPresent(CommandLineFlags.Add.class)) {
+            flags.addAll(Arrays.asList(element.getAnnotation(CommandLineFlags.Add.class).value()));
+        }
+
+        if (element.isAnnotationPresent(CommandLineFlags.Remove.class)) {
+            List<String> flagsToRemove =
+                    Arrays.asList(element.getAnnotation(CommandLineFlags.Remove.class).value());
+            for (String flagToRemove : flagsToRemove) {
+                // If your test fails here, you have tried to remove a command-line flag via
+                // CommandLineFlags.Remove that was loaded into CommandLine via something other
+                // than CommandLineFlags.Add (probably the command-line flag file).
+                Assert.assertFalse("Unable to remove command-line flag \"" + flagToRemove + "\".",
+                        CommandLine.getInstance().hasSwitch(flagToRemove));
+            }
+            flags.removeAll(flagsToRemove);
+        }
+
+        return flags;
+    }
+
     private CommandLineFlags() {}
 }
diff --git a/base/test/expectations/parser.cc b/base/test/expectations/parser.cc
index c7132e5..83c64c6 100644
--- a/base/test/expectations/parser.cc
+++ b/base/test/expectations/parser.cc
@@ -39,7 +39,7 @@
 Parser::StateFunc Parser::Start() {
   // If at the start of a line is whitespace, skip it and arrange to come back
   // here.
-  if (IsAsciiWhitespace(*pos_))
+  if (base::IsAsciiWhitespace(*pos_))
     return SkipWhitespaceAndNewLines(&Parser::Start);
 
   // Handle comments at the start of lines.
@@ -161,7 +161,7 @@
 
 Parser::StateFunc Parser::ExtractString(StateFunc success) {
   const char* start = pos_;
-  while (!IsAsciiWhitespace(*pos_) && *pos_ != ']' && HasNext()) {
+  while (!base::IsAsciiWhitespace(*pos_) && *pos_ != ']' && HasNext()) {
     ++pos_;
     if (*pos_ == '#') {
       return SyntaxError("Unexpected start of comment");
@@ -179,7 +179,7 @@
 }
 
 Parser::StateFunc Parser::SkipWhitespaceAndNewLines(Parser::StateFunc next) {
-  while (IsAsciiWhitespace(*pos_) && HasNext()) {
+  while (base::IsAsciiWhitespace(*pos_) && HasNext()) {
     if (*pos_ == '\n') {
       ++line_number_;
     }
diff --git a/base/test/histogram_tester.cc b/base/test/histogram_tester.cc
index ea738b0..0eba3a9 100644
--- a/base/test/histogram_tester.cc
+++ b/base/test/histogram_tester.cc
@@ -73,6 +73,19 @@
   }
 }
 
+std::vector<Bucket> HistogramTester::GetAllSamples(const std::string& name) {
+  std::vector<Bucket> samples;
+  scoped_ptr<HistogramSamples> snapshot =
+      GetHistogramSamplesSinceCreation(name);
+  for (auto it = snapshot->Iterator(); !it->Done(); it->Next()) {
+    HistogramBase::Sample sample;
+    HistogramBase::Count count;
+    it->Get(&sample, nullptr, &count);
+    samples.push_back(Bucket(sample, count));
+  }
+  return samples;
+}
+
 scoped_ptr<HistogramSamples> HistogramTester::GetHistogramSamplesSinceCreation(
     const std::string& histogram_name) {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(histogram_name);
@@ -120,4 +133,12 @@
       << expected_count << "). It has (" << actual_count << ").";
 }
 
+bool Bucket::operator==(const Bucket& other) const {
+  return min == other.min && count == other.count;
+}
+
+void PrintTo(const Bucket& bucket, std::ostream* os) {
+  *os << "Bucket " << bucket.min << ": " << bucket.count;
+}
+
 }  // namespace base
diff --git a/base/test/histogram_tester.h b/base/test/histogram_tester.h
index 96317f9..7ac7ca6 100644
--- a/base/test/histogram_tester.h
+++ b/base/test/histogram_tester.h
@@ -6,7 +6,10 @@
 #define BASE_TEST_HISTOGRAM_TESTER_H_
 
 #include <map>
+#include <ostream>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
@@ -15,6 +18,7 @@
 
 namespace base {
 
+struct Bucket;
 class HistogramSamples;
 
 // HistogramTester provides a simple interface for examining histograms, UMA
@@ -47,6 +51,24 @@
   void ExpectTotalCount(const std::string& name,
                         base::HistogramBase::Count count) const;
 
+  // Returns a list of all of the buckets recorded since creation of this
+  // object, as vector<Bucket>, where the Bucket represents the min boundary of
+  // the bucket and the count of samples recorded to that bucket since creation.
+  //
+  // Example usage, using gMock:
+  //   EXPECT_THAT(histogram_tester.GetAllSamples("HistogramName"),
+  //               ElementsAre(Bucket(1, 5), Bucket(2, 10), Bucket(3, 5)));
+  //
+  // If you build the expected list programmatically, you can use ContainerEq:
+  //   EXPECT_THAT(histogram_tester.GetAllSamples("HistogramName"),
+  //               ContainerEq(expected_buckets));
+  //
+  // or EXPECT_EQ if you prefer not to depend on gMock, at the expense of a
+  // slightly less helpful failure message:
+  //   EXPECT_EQ(expected_buckets,
+  //             histogram_tester.GetAllSamples("HistogramName"));
+  std::vector<Bucket> GetAllSamples(const std::string& name);
+
   // Access a modified HistogramSamples containing only what has been logged
   // to the histogram since the creation of this object.
   scoped_ptr<HistogramSamples> GetHistogramSamplesSinceCreation(
@@ -76,6 +98,18 @@
   DISALLOW_COPY_AND_ASSIGN(HistogramTester);
 };
 
+struct Bucket {
+  Bucket(base::HistogramBase::Sample min, base::HistogramBase::Count count)
+      : min(min), count(count) {}
+
+  bool operator==(const Bucket& other) const;
+
+  base::HistogramBase::Sample min;
+  base::HistogramBase::Count count;
+};
+
+void PrintTo(const Bucket& value, std::ostream* os);
+
 }  // namespace base
 
 #endif  // BASE_TEST_HISTOGRAM_TESTER_H_
diff --git a/base/test/histogram_tester_unittest.cc b/base/test/histogram_tester_unittest.cc
index a03ee13..f875527 100644
--- a/base/test/histogram_tester_unittest.cc
+++ b/base/test/histogram_tester_unittest.cc
@@ -5,16 +5,20 @@
 #include "base/test/histogram_tester.h"
 
 #include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/histogram_samples.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 
+using ::testing::ElementsAre;
+
 const std::string kHistogram1 = "Test1";
 const std::string kHistogram2 = "Test2";
 const std::string kHistogram3 = "Test3";
 const std::string kHistogram4 = "Test4";
+const std::string kHistogram5 = "Test5";
 
 typedef testing::Test HistogramTesterTest;
 
@@ -78,4 +82,15 @@
   tester.ExpectTotalCount(kHistogram4, 1);
 }
 
+TEST_F(HistogramTesterTest, TestGetAllSamples) {
+  HistogramTester tester;
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 2, 5);
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 3, 5);
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 3, 5);
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 5, 5);
+
+  EXPECT_THAT(tester.GetAllSamples(kHistogram5),
+              ElementsAre(Bucket(2, 1), Bucket(3, 2), Bucket(5, 1)));
+}
+
 }  // namespace base
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 7f258f5..7c0bc4e 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -25,6 +25,7 @@
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/pattern.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -569,7 +570,7 @@
           snippet_lines.begin() + truncated_size);
       snippet_lines.insert(snippet_lines.begin(), "<truncated>");
     }
-    fprintf(stdout, "%s", JoinString(snippet_lines, "\n").c_str());
+    fprintf(stdout, "%s", base::JoinString(snippet_lines, "\n").c_str());
     fflush(stdout);
   }
 
diff --git a/base/test/launcher/test_launcher_ios.cc b/base/test/launcher/test_launcher_ios.cc
index ecd31ae..3179bb3 100644
--- a/base/test/launcher/test_launcher_ios.cc
+++ b/base/test/launcher/test_launcher_ios.cc
@@ -121,7 +121,7 @@
     base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
     cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
     cmd_line.AppendSwitchASCII(base::kGTestFilterFlag,
-                               JoinString(test_names, ":"));
+                               base::JoinString(test_names, ":"));
     return cmd_line;
   }
 
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.cc b/base/test/launcher/test_launcher_nacl_nonsfi.cc
index fa52604..173e552 100644
--- a/base/test/launcher/test_launcher_nacl_nonsfi.cc
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.cc
@@ -112,8 +112,8 @@
     base::CommandLine cmd_line(test_path_);
     cmd_line.AppendSwitchPath(
         switches::kTestLauncherOutput, output_file);
-    cmd_line.AppendSwitchASCII(
-        base::kGTestFilterFlag, JoinString(test_names, ":"));
+    cmd_line.AppendSwitchASCII(base::kGTestFilterFlag,
+                               base::JoinString(test_names, ":"));
     return cmd_line;
   }
 
diff --git a/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc
index 32502f2..7623ce4 100644
--- a/base/test/test_pending_task_unittest.cc
+++ b/base/test/test_pending_task_unittest.cc
@@ -10,7 +10,7 @@
 #include "testing/gtest/include/gtest/gtest-spi.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
+namespace base {
 
 TEST(TestPendingTaskTest, TraceSupport) {
   base::TestPendingTask task;
@@ -52,4 +52,4 @@
       << task_first << ".ShouldRunBefore(" << task_after << ")\n";
 }
 
-}  // namespace
+}  // namespace base
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
index e3b1ffc..336cc45 100644
--- a/base/test/test_reg_util_win.cc
+++ b/base/test/test_reg_util_win.cc
@@ -7,6 +7,7 @@
 #include "base/guid.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,8 +33,10 @@
                                                         test_key_root.c_str());
   for (; iterator_test_root_key.Valid(); ++iterator_test_root_key) {
     base::string16 key_name = iterator_test_root_key.Name();
-    std::vector<base::string16> tokens;
-    if (!Tokenize(key_name, base::string16(kTimestampDelimiter), &tokens))
+    std::vector<base::string16> tokens =
+        base::SplitString(key_name, kTimestampDelimiter, base::KEEP_WHITESPACE,
+                          base::SPLIT_WANT_NONEMPTY);
+    if (tokens.empty())
       continue;
     int64 key_name_as_number = 0;
 
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index b6fb2ef..aef6906 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -332,7 +332,7 @@
   i18n::SetICUDefaultLocale("en_US");
 #else
   std::string default_locale(uloc_getDefault());
-  if (EndsWith(default_locale, "POSIX", false))
+  if (EndsWith(default_locale, "POSIX", CompareCase::INSENSITIVE_ASCII))
     i18n::SetICUDefaultLocale("en_US");
 #endif
 #endif
diff --git a/base/test/test_support_ios.mm b/base/test/test_support_ios.mm
index 3b31da6..9e82612 100644
--- a/base/test/test_support_ios.mm
+++ b/base/test/test_support_ios.mm
@@ -80,6 +80,10 @@
   label.textAlignment = NSTextAlignmentCenter;
   [window_ addSubview:label];
 
+  // An NSInternalInconsistencyException is thrown if the app doesn't have a
+  // root view controller. Set an empty one here.
+  [window_ setRootViewController:[[[UIViewController alloc] init] autorelease]];
+
   if ([self shouldRedirectOutputToFile])
     [self redirectOutput];
 
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index e46c2a5..93d7f30 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -10,6 +10,7 @@
 
 #include "base/json/json_reader.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/pattern.h"
 #include "base/values.h"
 
 namespace trace_analyzer {
@@ -321,17 +322,17 @@
   switch (operator_) {
     case OP_EQ:
       if (right().is_pattern_)
-        *result = MatchPattern(lhs, rhs);
+        *result = base::MatchPattern(lhs, rhs);
       else if (left().is_pattern_)
-        *result = MatchPattern(rhs, lhs);
+        *result = base::MatchPattern(rhs, lhs);
       else
         *result = (lhs == rhs);
       return true;
     case OP_NE:
       if (right().is_pattern_)
-        *result = !MatchPattern(lhs, rhs);
+        *result = !base::MatchPattern(lhs, rhs);
       else if (left().is_pattern_)
-        *result = !MatchPattern(rhs, lhs);
+        *result = !base::MatchPattern(rhs, lhs);
       else
         *result = (lhs != rhs);
       return true;
diff --git a/base/third_party/nspr/prtime.cc b/base/third_party/nspr/prtime.cc
index 9335b01..a7c5a3a 100644
--- a/base/third_party/nspr/prtime.cc
+++ b/base/third_party/nspr/prtime.cc
@@ -107,9 +107,9 @@
     static const PRTime kSecondsToMicroseconds = static_cast<PRTime>(1000000);
 #if defined(OS_WIN)
    // Create the system struct representing our exploded time.
-    SYSTEMTIME st = {0};
-    FILETIME ft = {0};
-    ULARGE_INTEGER uli = {0};
+    SYSTEMTIME st = {};
+    FILETIME ft = {};
+    ULARGE_INTEGER uli = {};
 
     st.wYear = exploded->tm_year;
     st.wMonth = static_cast<WORD>(exploded->tm_month + 1);
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
index b25f747..f4861df 100644
--- a/base/third_party/symbolize/symbolize.cc
+++ b/base/third_party/symbolize/symbolize.cc
@@ -651,7 +651,8 @@
 
   // Handle negative numbers (only for base 10).
   if (i < 0 && base == 10) {
-    j = -i;
+    // This does "j = -i" while avoiding integer overflow.
+    j = static_cast<uintptr_t>(-(i + 1)) + 1;
 
     // Make sure we can write the '-' character.
     if (++n > sz) {
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 3468f45..0b92265 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -89,6 +89,7 @@
         id_(id) {
   }
 
+  // TODO(toyoshim): Remove id() and use PlatformThread::CurrentId() instead.
   PlatformThreadId id() const {
     return id_;
   }
@@ -112,8 +113,8 @@
 
 const PlatformThreadId kInvalidThreadId(0);
 
-// Valid values for SetThreadPriority(), listed in increasing order of
-// importance.
+// Valid values for priority of Thread::Options and SimpleThread::Options, and
+// SetCurrentThreadPriority(), listed in increasing order of importance.
 enum class ThreadPriority {
   // Suitable for threads that shouldn't disrupt high priority work.
   BACKGROUND,
@@ -176,8 +177,7 @@
                      PlatformThreadHandle* thread_handle);
 
   // CreateWithPriority() does the same thing as Create() except the priority of
-  // the thread is set based on |priority|.  Can be used in place of Create()
-  // followed by SetThreadPriority().
+  // the thread is set based on |priority|.
   static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
                                  PlatformThreadHandle* thread_handle,
                                  ThreadPriority priority);
@@ -192,15 +192,15 @@
   // |thread_handle|.
   static void Join(PlatformThreadHandle thread_handle);
 
-  // Toggles the target thread's priority at runtime.  Prefer
-  // CreateWithPriority() to set the thread's initial priority.
-  // NOTE: The call may fail if the caller thread is not the same as the
-  // target thread on POSIX.  For example, seccomp-bpf blocks it by default
-  // in the sandbox.
-  static void SetThreadPriority(PlatformThreadHandle handle,
-                                ThreadPriority priority);
+  // Toggles the current thread's priority at runtime. A thread may not be able
+  // to raise its priority back up after lowering it if the process does not
+  // have a proper permission, e.g. CAP_SYS_NICE on Linux.
+  // Since changing other threads' priority is not permitted in favor of
+  // security, this interface is restricted to change only the current thread
+  // priority (https://crbug.com/399473).
+  static void SetCurrentThreadPriority(ThreadPriority priority);
 
-  static ThreadPriority GetThreadPriority(PlatformThreadHandle handle);
+  static ThreadPriority GetCurrentThreadPriority();
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index 11e5e2e..176a6bd 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -23,29 +23,21 @@
 
 namespace internal {
 
-// These nice values are taken from Android, which uses nice values like linux,
-// but defines some preset nice values.
-//   Process.THREAD_PRIORITY_AUDIO = -16
-//   Process.THREAD_PRIORITY_BACKGROUND = 10
-//   Process.THREAD_PRIORITY_DEFAULT = 0;
-//   Process.THREAD_PRIORITY_DISPLAY = -4;
-//   Process.THREAD_PRIORITY_FOREGROUND = -2;
-//   Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
-//   Process.THREAD_PRIORITY_LOWEST = 19;
-//   Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
-//   Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
-//   Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
-// We use -6 for display, but we may want to split this into urgent (-8) and
-// non-urgent (-4).
+// - BACKGROUND is 9 due to it being the nicest value we can use that's still
+// above an Android system threshold that enables heavy throttling starting at
+// 10; we want to be lower-priority than Chrome's other threads without
+// incurring this behavior.
+// - DISPLAY is -6 due to being midway between Android's DISPLAY (-4) and
+// URGENT_DISPLAY (-8).
+// - REALTIME_AUDIO corresponds to Android's THREAD_PRIORITY_AUDIO = -16 value.
 const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
-    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::BACKGROUND, 9},
     {ThreadPriority::NORMAL, 0},
     {ThreadPriority::DISPLAY, -6},
     {ThreadPriority::REALTIME_AUDIO, -16},
 };
 
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
   // On Android, we set the Audio priority through JNI as Audio priority
   // will also allow the process to run while it is backgrounded.
   if (priority == ThreadPriority::REALTIME_AUDIO) {
@@ -56,8 +48,8 @@
   return false;
 }
 
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority) {
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
+  // See http://crbug.com/505474.
   NOTIMPLEMENTED();
   return false;
 }
@@ -88,8 +80,7 @@
 void InitOnThread() {
   // Threads on linux/android may inherit their priority from the thread
   // where they were created. This sets all new threads to the default.
-  PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
-                                    ThreadPriority::NORMAL);
+  PlatformThread::SetCurrentThreadPriority(ThreadPriority::NORMAL);
 }
 
 void TerminateOnThread() {
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
index f4fded0..e29e865 100644
--- a/base/threading/platform_thread_freebsd.cc
+++ b/base/threading/platform_thread_freebsd.cc
@@ -36,11 +36,8 @@
     {ThreadPriority::REALTIME_AUDIO, -10},
 }
 
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
 #if !defined(OS_NACL)
-  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
-  // of |handle|. http://crbug.com/468793.
   return priority == ThreadPriority::REALTIME_AUDIO &&
          pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
 #else
@@ -48,11 +45,8 @@
 #endif
 }
 
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority) {
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
 #if !defined(OS_NACL)
-  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
-  // of |handle|. http://crbug.com/468793.
   int maybe_sched_rr = 0;
   struct sched_param maybe_realtime_prio = {0};
   if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
index 62006ce..05a8d1e 100644
--- a/base/threading/platform_thread_internal_posix.h
+++ b/base/threading/platform_thread_internal_posix.h
@@ -26,17 +26,15 @@
 ThreadPriority NiceValueToThreadPriority(int nice_value);
 
 // Allows platform specific tweaks to the generic POSIX solution for
-// SetThreadPriority. Returns true if the platform-specific implementation
-// handled this |priority| change, false if the generic implementation should
-// instead proceed.
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority);
+// SetCurrentThreadPriority. Returns true if the platform-specific
+// implementation handled this |priority| change, false if the generic
+// implementation should instead proceed.
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority);
 
-// Returns true if there is a platform-specific ThreadPriority set on |handle|
-// (and returns the actual ThreadPriority via |priority|). Returns false
-// otherwise, leaving |priority| untouched.
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority);
+// Returns true if there is a platform-specific ThreadPriority set on the
+// current thread (and returns the actual ThreadPriority via |priority|).
+// Returns false otherwise, leaving |priority| untouched.
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority);
 
 }  // namespace internal
 
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index 9f74374..48cf744 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -27,6 +27,7 @@
 namespace {
 #if !defined(OS_NACL)
 const struct sched_param kRealTimePrio = {8};
+const struct sched_param kResetPrio = {0};
 #endif
 }  // namespace
 
@@ -37,11 +38,18 @@
     {ThreadPriority::REALTIME_AUDIO, -10},
 };
 
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
 #if !defined(OS_NACL)
-  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
-  // of |handle|. http://crbug.com/468793.
+  ThreadPriority current_priority;
+  if (priority != ThreadPriority::REALTIME_AUDIO &&
+      GetCurrentThreadPriorityForPlatform(&current_priority) &&
+      current_priority == ThreadPriority::REALTIME_AUDIO) {
+    // If the pthread's round-robin scheduler is already enabled, and the new
+    // priority will use setpriority() instead, the pthread scheduler should be
+    // reset to use SCHED_OTHER so that setpriority() just works.
+    pthread_setschedparam(pthread_self(), SCHED_OTHER, &kResetPrio);
+    return false;
+  }
   return priority == ThreadPriority::REALTIME_AUDIO  &&
          pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
 #else
@@ -49,13 +57,10 @@
 #endif
 }
 
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority) {
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
 #if !defined(OS_NACL)
   int maybe_sched_rr = 0;
   struct sched_param maybe_realtime_prio = {0};
-  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
-  // of |handle|. http://crbug.com/468793.
   if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
                             &maybe_realtime_prio) == 0 &&
       maybe_sched_rr == SCHED_RR &&
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index 813cae2..1ecbcd6 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -155,10 +155,10 @@
 }  // anonymous namespace
 
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
-                                       ThreadPriority priority) {
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
   // Convert from pthread_t to mach thread identifier.
-  mach_port_t mach_thread_id = pthread_mach_thread_np(handle.platform_handle());
+  mach_port_t mach_thread_id =
+      pthread_mach_thread_np(PlatformThread::CurrentHandle().platform_handle());
 
   switch (priority) {
     case ThreadPriority::NORMAL:
@@ -174,7 +174,7 @@
 }
 
 // static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
   NOTIMPLEMENTED();
   return ThreadPriority::NORMAL;
 }
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 0d821a9..f3a835e 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -58,10 +58,8 @@
   if (!thread_params->joinable)
     base::ThreadRestrictions::SetSingletonAllowed(false);
 
-  if (thread_params->priority != ThreadPriority::NORMAL) {
-    PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
-                                      thread_params->priority);
-  }
+  if (thread_params->priority != ThreadPriority::NORMAL)
+    PlatformThread::SetCurrentThreadPriority(thread_params->priority);
 
   // Stash the id in the handle so the calling thread has a complete
   // handle, and unblock the parent thread.
@@ -231,16 +229,15 @@
   CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL));
 }
 
-// Mac has its own Set/GetThreadPriority() implementations.
+// Mac has its own Set/GetCurrentThreadPriority() implementations.
 #if !defined(OS_MACOSX)
 
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
-                                       ThreadPriority priority) {
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
 #if defined(OS_NACL)
   NOTIMPLEMENTED();
 #else
-  if (internal::SetThreadPriorityForPlatform(handle, priority))
+  if (internal::SetCurrentThreadPriorityForPlatform(priority))
     return;
 
   // setpriority(2) should change the whole thread group's (i.e. process)
@@ -249,39 +246,34 @@
   // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
   // attribute". Also, 0 is prefered to the current thread id since it is
   // equivalent but makes sandboxing easier (https://crbug.com/399473).
-  DCHECK_NE(handle.id(), kInvalidThreadId);
   const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
-  const PlatformThreadId current_id = PlatformThread::CurrentId();
-  if (setpriority(PRIO_PROCESS, handle.id() == current_id ? 0 : handle.id(),
-                  nice_setting)) {
-    DVPLOG(1) << "Failed to set nice value of thread (" << handle.id()
-              << ") to " << nice_setting;
+  if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
+    DVPLOG(1) << "Failed to set nice value of thread ("
+              << PlatformThread::CurrentId() << ") to " << nice_setting;
   }
 #endif  // defined(OS_NACL)
 }
 
 // static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
 #if defined(OS_NACL)
   NOTIMPLEMENTED();
   return ThreadPriority::NORMAL;
 #else
-  // Mirrors SetThreadPriority()'s implementation.
+  // Mirrors SetCurrentThreadPriority()'s implementation.
   ThreadPriority platform_specific_priority;
-  if (internal::GetThreadPriorityForPlatform(handle,
-                                             &platform_specific_priority)) {
+  if (internal::GetCurrentThreadPriorityForPlatform(
+          &platform_specific_priority)) {
     return platform_specific_priority;
   }
 
-  DCHECK_NE(handle.id(), kInvalidThreadId);
-  const PlatformThreadId current_id = PlatformThread::CurrentId();
   // Need to clear errno before calling getpriority():
   // http://man7.org/linux/man-pages/man2/getpriority.2.html
   errno = 0;
-  int nice_value =
-      getpriority(PRIO_PROCESS, handle.id() == current_id ? 0 : handle.id());
+  int nice_value = getpriority(PRIO_PROCESS, 0);
   if (errno != 0) {
-    DVPLOG(1) << "Failed to get nice value of thread (" << handle.id() << ")";
+    DVPLOG(1) << "Failed to get nice value of thread ("
+              << PlatformThread::CurrentId() << ")";
     return ThreadPriority::NORMAL;
   }
 
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index c4b3d5d..0fd9bc4 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -8,7 +8,10 @@
 #include "base/threading/platform_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_WIN)
+#if defined(OS_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#elif defined(OS_WIN)
 #include <windows.h>
 #endif
 
@@ -16,6 +19,8 @@
 
 // Trivial tests that thread runs and doesn't crash on create and join ---------
 
+namespace {
+
 class TrivialThread : public PlatformThread::Delegate {
  public:
   TrivialThread() : did_run_(false) {}
@@ -30,6 +35,8 @@
   DISALLOW_COPY_AND_ASSIGN(TrivialThread);
 };
 
+}  // namespace
+
 TEST(PlatformThreadTest, Trivial) {
   TrivialThread thread;
   PlatformThreadHandle handle;
@@ -56,11 +63,13 @@
 
 // Tests of basic thread functions ---------------------------------------------
 
+namespace {
+
 class FunctionTestThread : public PlatformThread::Delegate {
  public:
   FunctionTestThread()
       : thread_id_(kInvalidThreadId),
-        thread_started_(true, false),
+        termination_ready_(true, false),
         terminate_thread_(true, false),
         done_(false) {}
   ~FunctionTestThread() override {
@@ -70,8 +79,9 @@
         << "WaitableEvent blocking the underlying thread's main.";
   }
 
-  // Grabs |thread_id_|, signals |thread_started_|, and then waits for
-  // |terminate_thread_| to be signaled before exiting.
+  // Grabs |thread_id_|, runs an optional test on that thread, signals
+  // |termination_ready_|, and then waits for |terminate_thread_| to be
+  // signaled before exiting.
   void ThreadMain() override {
     thread_id_ = PlatformThread::CurrentId();
     EXPECT_NE(thread_id_, kInvalidThreadId);
@@ -79,39 +89,44 @@
     // Make sure that the thread ID is the same across calls.
     EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
 
-    thread_started_.Signal();
+    // Run extra tests.
+    RunTest();
 
+    termination_ready_.Signal();
     terminate_thread_.Wait();
 
     done_ = true;
   }
 
   PlatformThreadId thread_id() const {
-    EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown";
+    EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
     return thread_id_;
   }
 
-  bool IsRunning() const {
-    return thread_started_.IsSignaled() && !done_;
-  }
+  bool IsRunning() const { return termination_ready_.IsSignaled() && !done_; }
 
-  // Blocks until this thread is started.
-  void WaitForThreadStart() { thread_started_.Wait(); }
+  // Blocks until this thread is started and ready to be terminated.
+  void WaitForTerminationReady() { termination_ready_.Wait(); }
 
-  // Mark this thread for termination (callers must then join this thread to be
+  // Marks this thread for termination (callers must then join this thread to be
   // guaranteed of termination).
   void MarkForTermination() { terminate_thread_.Signal(); }
 
  private:
+  // Runs an optional test on the newly created thread.
+  virtual void RunTest() {}
+
   PlatformThreadId thread_id_;
 
-  mutable WaitableEvent thread_started_;
+  mutable WaitableEvent termination_ready_;
   WaitableEvent terminate_thread_;
   bool done_;
 
   DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
 };
 
+}  // namespace
+
 TEST(PlatformThreadTest, Function) {
   PlatformThreadId main_thread_id = PlatformThread::CurrentId();
 
@@ -120,7 +135,7 @@
 
   ASSERT_FALSE(thread.IsRunning());
   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-  thread.WaitForThreadStart();
+  thread.WaitForTerminationReady();
   ASSERT_TRUE(thread.IsRunning());
   EXPECT_NE(thread.thread_id(), main_thread_id);
 
@@ -144,7 +159,7 @@
   for (size_t n = 0; n < arraysize(thread); n++)
     ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
   for (size_t n = 0; n < arraysize(thread); n++)
-    thread[n].WaitForThreadStart();
+    thread[n].WaitForTerminationReady();
 
   for (size_t n = 0; n < arraysize(thread); n++) {
     ASSERT_TRUE(thread[n].IsRunning());
@@ -170,106 +185,85 @@
 namespace {
 
 const ThreadPriority kThreadPriorityTestValues[] = {
-// Disable non-normal priority toggling on POSIX as it appears to be broken
-// (http://crbug.com/468793). This is prefered to disabling the tests altogether
-// on POSIX as it at least provides coverage for running this code under
-// "normal" priority.
-#if !defined(OS_POSIX)
-    ThreadPriority::DISPLAY,
+// The order should be higher to lower to cover as much cases as possible on
+// Linux trybots running without CAP_SYS_NICE permission.
+#if !defined(OS_ANDROID)
+    // PlatformThread::GetCurrentThreadPriority() on Android does not support
+    // REALTIME_AUDIO case. See http://crbug.com/505474.
     ThreadPriority::REALTIME_AUDIO,
-    // Keep BACKGROUND second to last to test backgrounding from other
-    // priorities.
-    ThreadPriority::BACKGROUND,
-#endif  // !defined(OS_POSIX)
-    // Keep NORMAL last to test unbackgrounding.
-    ThreadPriority::NORMAL
+#endif
+    ThreadPriority::DISPLAY,
+    // This redundant BACKGROUND priority is to test backgrounding from other
+    // priorities, and unbackgrounding.
+    ThreadPriority::BACKGROUND, ThreadPriority::NORMAL,
+    ThreadPriority::BACKGROUND};
+
+bool IsBumpingPriorityAllowed() {
+#if defined(OS_POSIX)
+  // Only root can raise thread priority on POSIX environment. On Linux, users
+  // who have CAP_SYS_NICE permission also can raise the thread priority, but
+  // libcap.so would be needed to check the capability.
+  return geteuid() == 0;
+#else
+  return true;
+#endif
+}
+
+class ThreadPriorityTestThread : public FunctionTestThread {
+ public:
+  ThreadPriorityTestThread() = default;
+  ~ThreadPriorityTestThread() override = default;
+
+ private:
+  void RunTest() override {
+    // Confirm that the current thread's priority is as expected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetCurrentThreadPriority());
+
+    // Toggle each supported priority on the current thread and confirm it
+    // affects it.
+    const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
+    for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+      SCOPED_TRACE(i);
+      if (!bumping_priority_allowed &&
+          kThreadPriorityTestValues[i] >
+              PlatformThread::GetCurrentThreadPriority()) {
+        continue;
+      }
+
+      // Alter and verify the current thread's priority.
+      PlatformThread::SetCurrentThreadPriority(kThreadPriorityTestValues[i]);
+      EXPECT_EQ(kThreadPriorityTestValues[i],
+                PlatformThread::GetCurrentThreadPriority());
+    }
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
 };
 
 }  // namespace
 
-// Test changing another thread's priority.
-// NOTE: This test is partially disabled on POSIX, see note above and
-// http://crbug.com/468793.
-TEST(PlatformThreadTest, ThreadPriorityOtherThread) {
-  PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+#if defined(OS_MACOSX)
+// PlatformThread::GetCurrentThreadPriority() is not implemented on OS X.
+#define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
+#else
+#define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
+#endif
 
-  // Confirm that the current thread's priority is as expected.
-  EXPECT_EQ(ThreadPriority::NORMAL,
-            PlatformThread::GetThreadPriority(current_handle));
-
-  // Create a test thread.
-  FunctionTestThread thread;
-  PlatformThreadHandle handle;
-  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-  thread.WaitForThreadStart();
-  EXPECT_NE(thread.thread_id(), kInvalidThreadId);
-  EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
-
-  // New threads should get normal priority by default.
-  EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
-
-  // Toggle each supported priority on the test thread and confirm it only
-  // affects it (and not the current thread).
-  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
-    SCOPED_TRACE(i);
-
-    // Alter and verify the test thread's priority.
-    PlatformThread::SetThreadPriority(handle, kThreadPriorityTestValues[i]);
-    EXPECT_EQ(kThreadPriorityTestValues[i],
-              PlatformThread::GetThreadPriority(handle));
-
-    // Make sure the current thread was otherwise unaffected.
-    EXPECT_EQ(ThreadPriority::NORMAL,
-              PlatformThread::GetThreadPriority(current_handle));
-  }
-
-  thread.MarkForTermination();
-  PlatformThread::Join(handle);
-}
-
-// Test changing the current thread's priority (which has different semantics on
+// Test changing a created thread's priority (which has different semantics on
 // some platforms).
-// NOTE: This test is partially disabled on POSIX, see note above and
-// http://crbug.com/468793.
-TEST(PlatformThreadTest, ThreadPriorityCurrentThread) {
-  PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
-
-  // Confirm that the current thread's priority is as expected.
-  EXPECT_EQ(ThreadPriority::NORMAL,
-            PlatformThread::GetThreadPriority(current_handle));
-
-  // Create a test thread for verification purposes only.
-  FunctionTestThread thread;
+TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
+  ThreadPriorityTestThread thread;
   PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.IsRunning());
   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-  thread.WaitForThreadStart();
-  EXPECT_NE(thread.thread_id(), kInvalidThreadId);
-  EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
-
-  // Confirm that the new thread's priority is as expected.
-  EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
-
-  // Toggle each supported priority on the current thread and confirm it only
-  // affects it (and not the test thread).
-  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
-    SCOPED_TRACE(i);
-
-    // Alter and verify the current thread's priority.
-    PlatformThread::SetThreadPriority(current_handle,
-                                      kThreadPriorityTestValues[i]);
-    EXPECT_EQ(kThreadPriorityTestValues[i],
-              PlatformThread::GetThreadPriority(current_handle));
-
-    // Make sure the test thread was otherwise unaffected.
-    EXPECT_EQ(ThreadPriority::NORMAL,
-              PlatformThread::GetThreadPriority(handle));
-  }
-
-  // Restore current thread priority for follow-up tests.
-  PlatformThread::SetThreadPriority(current_handle, ThreadPriority::NORMAL);
+  thread.WaitForTerminationReady();
+  ASSERT_TRUE(thread.IsRunning());
 
   thread.MarkForTermination();
   PlatformThread::Join(handle);
+  ASSERT_FALSE(thread.IsRunning());
 }
 
 }  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index 395fc9e..be3f410 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -46,6 +46,7 @@
 struct ThreadParams {
   PlatformThread::Delegate* delegate;
   bool joinable;
+  ThreadPriority priority;
 };
 
 DWORD __stdcall ThreadFunc(void* params) {
@@ -54,6 +55,9 @@
   if (!thread_params->joinable)
     base::ThreadRestrictions::SetSingletonAllowed(false);
 
+  if (thread_params->priority != ThreadPriority::NORMAL)
+    PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+
   // Retrieve a copy of the thread handle to use as the key in the
   // thread name mapping.
   PlatformThreadHandle::Handle platform_handle;
@@ -86,12 +90,13 @@
   return NULL;
 }
 
-// CreateThreadInternal() matches PlatformThread::Create(), except that
-// |out_thread_handle| may be NULL, in which case a non-joinable thread is
+// CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except
+// that |out_thread_handle| may be NULL, in which case a non-joinable thread is
 // created.
 bool CreateThreadInternal(size_t stack_size,
                           PlatformThread::Delegate* delegate,
-                          PlatformThreadHandle* out_thread_handle) {
+                          PlatformThreadHandle* out_thread_handle,
+                          ThreadPriority priority) {
   unsigned int flags = 0;
   if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
     flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
@@ -102,6 +107,7 @@
   ThreadParams* params = new ThreadParams;
   params->delegate = delegate;
   params->joinable = out_thread_handle != NULL;
+  params->priority = priority;
 
   // Using CreateThread here vs _beginthreadex makes thread creation a bit
   // faster and doesn't require the loader lock to be available.  Our code will
@@ -185,23 +191,22 @@
 // static
 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
                             PlatformThreadHandle* thread_handle) {
-  DCHECK(thread_handle);
-  return CreateThreadInternal(stack_size, delegate, thread_handle);
+  return CreateWithPriority(stack_size, delegate, thread_handle,
+                            ThreadPriority::NORMAL);
 }
 
 // static
 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
                                         PlatformThreadHandle* thread_handle,
                                         ThreadPriority priority) {
-  bool result = Create(stack_size, delegate, thread_handle);
-  if (result)
-    SetThreadPriority(*thread_handle, priority);
-  return result;
+  DCHECK(thread_handle);
+  return CreateThreadInternal(stack_size, delegate, thread_handle, priority);
 }
 
 // static
 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
-  return CreateThreadInternal(stack_size, delegate, NULL);
+  return CreateThreadInternal(stack_size, delegate, NULL,
+                              ThreadPriority::NORMAL);
 }
 
 // static
@@ -231,10 +236,7 @@
 }
 
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
-                                       ThreadPriority priority) {
-  DCHECK(!handle.is_null());
-
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
   int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
   switch (priority) {
     case ThreadPriority::BACKGROUND:
@@ -258,16 +260,16 @@
 #ifndef NDEBUG
   const BOOL success =
 #endif
-      ::SetThreadPriority(handle.platform_handle(), desired_priority);
+      ::SetThreadPriority(PlatformThread::CurrentHandle().platform_handle(),
+                          desired_priority);
   DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
                             << desired_priority;
 }
 
 // static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
-  DCHECK(!handle.is_null());
-
-  int priority = ::GetThreadPriority(handle.platform_handle());
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+  int priority =
+      ::GetThreadPriority(PlatformThread::CurrentHandle().platform_handle());
   switch (priority) {
     case THREAD_PRIORITY_LOWEST:
       return ThreadPriority::BACKGROUND;
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
index a5b9580..d21ab78 100644
--- a/base/threading/post_task_and_reply_impl.h
+++ b/base/threading/post_task_and_reply_impl.h
@@ -25,6 +25,8 @@
 // may want base::WorkerPool.
 class PostTaskAndReplyImpl {
  public:
+  virtual ~PostTaskAndReplyImpl() = default;
+
   // Implementation for TaskRunner::PostTaskAndReply and
   // WorkerPool::PostTaskAndReply.
   bool PostTaskAndReply(const tracked_objects::Location& from_here,
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index 36548d3..2f0eb4d 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -59,8 +59,10 @@
  public:
   class BASE_EXPORT Options {
    public:
-    Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) { }
-    ~Options() { }
+    Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) {}
+    explicit Options(ThreadPriority priority)
+        : stack_size_(0), priority_(priority) {}
+    ~Options() {}
 
     // We use the standard compiler-supplied copy constructor.
 
@@ -109,12 +111,6 @@
   // Overridden from PlatformThread::Delegate:
   void ThreadMain() override;
 
-  // Only set priorities with a careful understanding of the consequences.
-  // This is meant for very limited use cases.
-  void SetThreadPriority(ThreadPriority priority) {
-    PlatformThread::SetThreadPriority(thread_, priority);
-  }
-
  private:
   const std::string name_prefix_;
   std::string name_;
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 63b07cb..9c4535b 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -94,8 +94,9 @@
     type = MessageLoop::TYPE_CUSTOM;
 
   message_loop_timer_slack_ = options.timer_slack;
-  message_loop_ = new MessageLoop(type, options.message_pump_factory);
-
+  scoped_ptr<MessageLoop> message_loop =
+      MessageLoop::CreateUnbound(type, options.message_pump_factory);
+  message_loop_ = message_loop.get();
   start_event_.reset(new WaitableEvent(false, false));
 
   // Hold the thread_lock_ while starting a new thread, so that we can make sure
@@ -111,13 +112,16 @@
     }
     if (!created) {
       DLOG(ERROR) << "failed to create thread";
-      delete message_loop_;
       message_loop_ = nullptr;
       start_event_.reset();
       return false;
     }
   }
 
+  // The ownership of message_loop is managemed by the newly created thread
+  // within the ThreadMain.
+  ignore_result(message_loop.release());
+
   DCHECK(message_loop_);
   return true;
 }
@@ -190,13 +194,6 @@
   return running_;
 }
 
-void Thread::SetPriority(ThreadPriority priority) {
-  // The thread must be started (and id known) for this to be
-  // compatible with all platforms.
-  DCHECK(message_loop_ != nullptr);
-  PlatformThread::SetThreadPriority(thread_, priority);
-}
-
 void Thread::Run(MessageLoop* message_loop) {
   message_loop->Run();
 }
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 0bd5d12..5126491 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -155,25 +155,13 @@
   //
   MessageLoop* message_loop() const { return message_loop_; }
 
-  // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
-  // PostTask methods to execute code on the thread. Returns NULL if the thread
-  // is not running (e.g. before Start or after Stop have been called). Callers
-  // can hold on to this even after the thread is gone; in this situation,
-  // attempts to PostTask() will fail.
-  //
-  // Note: This method is deprecated. Callers should call task_runner() instead
-  // and use the TaskRunner interfaces for safely interfacing with the Thread.
-  scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
-    return message_loop_ ? message_loop_->message_loop_proxy() : NULL;
-  }
-
   // Returns a TaskRunner for this thread. Use the TaskRunner's PostTask
   // methods to execute code on the thread. Returns NULL if the thread is not
   // running (e.g. before Start or after Stop have been called). Callers can
   // hold on to this even after the thread is gone; in this situation, attempts
   // to PostTask() will fail.
   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
-    return message_loop_->task_runner();
+    return message_loop_ ? message_loop_->task_runner() : nullptr;
   }
 
   // Returns the name of this thread (for display in debugger too).
@@ -188,9 +176,6 @@
   // Returns true if the thread has been started, and not yet stopped.
   bool IsRunning() const;
 
-  // Sets the thread priority. The thread must already be started.
-  void SetPriority(ThreadPriority priority);
-
  protected:
   // Called just prior to starting the message loop
   virtual void Init() {}
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 54f50eb..6f3d705 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -58,6 +58,7 @@
 }
 }
 namespace net {
+class NetworkChangeNotifierMac;
 namespace internal {
 class AddressTrackerLinux;
 }
@@ -206,6 +207,7 @@
   friend class disk_cache::BackendImpl;           // http://crbug.com/74623
   friend class disk_cache::InFlightIO;            // http://crbug.com/74623
   friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
+  friend class net::NetworkChangeNotifierMac;       // http://crbug.com/125097
   friend class ::BrowserProcessImpl;              // http://crbug.com/125207
   friend class ::NativeBackendKWallet;            // http://crbug.com/125331
   // END USAGE THAT NEEDS TO BE FIXED.
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index e86c758..3c35416 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -234,3 +234,8 @@
   EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
   EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
 }
+
+TEST_F(ThreadTest, ThreadNotStarted) {
+  Thread a("Inert");
+  EXPECT_EQ(nullptr, a.task_runner());
+}
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
index bc016ce..71b1a2b 100644
--- a/base/threading/worker_pool.cc
+++ b/base/threading/worker_pool.cc
@@ -21,6 +21,7 @@
   explicit PostTaskAndReplyWorkerPool(bool task_is_slow)
       : task_is_slow_(task_is_slow) {
   }
+  ~PostTaskAndReplyWorkerPool() override = default;
 
  private:
   bool PostTask(const tracked_objects::Location& from_here,
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
index 7826fc6..fc82c62 100644
--- a/base/time/time_posix.cc
+++ b/base/time/time_posix.cc
@@ -17,7 +17,6 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "build/build_config.h"
 
 #if defined(OS_ANDROID)
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index 9144483..e904460 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -428,7 +428,7 @@
 }
 
 void InitializeNowFunctionPointers() {
-  LARGE_INTEGER ticks_per_sec = {0};
+  LARGE_INTEGER ticks_per_sec = {};
   if (!QueryPerformanceFrequency(&ticks_per_sec))
     ticks_per_sec.QuadPart = 0;
 
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index e6392e2..663d7ba 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -13,6 +13,7 @@
     "memory_dump_manager.cc",
     "memory_dump_manager.h",
     "memory_dump_provider.h",
+    "memory_dump_request_args.cc",
     "memory_dump_request_args.h",
     "memory_dump_session_state.cc",
     "memory_dump_session_state.h",
@@ -39,6 +40,8 @@
     "trace_event_impl_constants.cc",
     "trace_event_memory.cc",
     "trace_event_memory.h",
+    "trace_event_memory_overhead.cc",
+    "trace_event_memory_overhead.h",
     "trace_event_synthetic_delay.cc",
     "trace_event_synthetic_delay.h",
     "trace_event_system_stats_monitor.cc",
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index 92d513f..4304f28 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -32,14 +32,13 @@
   struct mallinfo info = mallinfo();
   DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
 
-  // When the system allocator is implemented by tcmalloc, the total physical
+  // When the system allocator is implemented by tcmalloc, the total heap
   // 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.
   MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
-  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
-                        MemoryAllocatorDump::kUnitsBytes,
+  outer_dump->AddScalar("heap_virtual_size", MemoryAllocatorDump::kUnitsBytes,
                         info.arena + info.hblkhd);
 
   // Total allocated space is given by |uordblks|.
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index 5d11bb0..4037f94 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -15,28 +15,7 @@
 namespace base {
 namespace trace_event {
 
-namespace {
-// Returns the c-string pointer from a dictionary value without performing extra
-// std::string copies. The ptr will be valid as long as the value exists.
-bool GetDictionaryValueAsCStr(const DictionaryValue* dict_value,
-                              const std::string& key,
-                              const char** out_cstr) {
-  const Value* value = nullptr;
-  const StringValue* str_value = nullptr;
-  if (!dict_value->GetWithoutPathExpansion(key, &value))
-    return false;
-  if (!value->GetAsString(&str_value))
-    return false;
-  *out_cstr = str_value->GetString().c_str();
-  return true;
-}
-}  // namespace
-
-// TODO(primiano): remove kName{Inner,Outer}Size below after all the existing
-// dump providers have been rewritten.
 const char MemoryAllocatorDump::kNameSize[] = "size";
-const char MemoryAllocatorDump::kNameInnerSize[] = "inner_size";
-const char MemoryAllocatorDump::kNameOuterSize[] = "outer_size";
 const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
 const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
 const char MemoryAllocatorDump::kTypeString[] = "string";
@@ -48,6 +27,7 @@
                                          const MemoryAllocatorDumpGuid& guid)
     : absolute_name_(absolute_name),
       process_memory_dump_(process_memory_dump),
+      attributes_(new TracedValue),
       guid_(guid) {
   // The |absolute_name| cannot be empty.
   DCHECK(!absolute_name.empty());
@@ -73,73 +53,47 @@
                               "%d:%s",
                               TraceLog::GetInstance()->process_id(),
                               absolute_name.c_str()))) {
+  string_conversion_buffer_.reserve(16);
 }
 
 MemoryAllocatorDump::~MemoryAllocatorDump() {
 }
 
-void MemoryAllocatorDump::Add(const std::string& name,
-                              const char* type,
-                              const char* units,
-                              scoped_ptr<Value> value) {
-  scoped_ptr<DictionaryValue> attribute(new DictionaryValue());
-  DCHECK(!attributes_.HasKey(name));
-  attribute->SetStringWithoutPathExpansion("type", type);
-  attribute->SetStringWithoutPathExpansion("units", units);
-  attribute->SetWithoutPathExpansion("value", value.Pass());
-  attributes_.SetWithoutPathExpansion(name, attribute.Pass());
-}
-
-bool MemoryAllocatorDump::Get(const std::string& name,
-                              const char** out_type,
-                              const char** out_units,
-                              const Value** out_value) const {
-  const DictionaryValue* attribute = nullptr;
-  if (!attributes_.GetDictionaryWithoutPathExpansion(name, &attribute))
-    return false;
-
-  if (!GetDictionaryValueAsCStr(attribute, "type", out_type))
-    return false;
-
-  if (!GetDictionaryValueAsCStr(attribute, "units", out_units))
-    return false;
-
-  if (!attribute->GetWithoutPathExpansion("value", out_value))
-    return false;
-
-  return true;
-}
-
-void MemoryAllocatorDump::AddScalar(const std::string& name,
+void MemoryAllocatorDump::AddScalar(const char* name,
                                     const char* units,
                                     uint64 value) {
-  scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
-  Add(name, kTypeScalar, units, hex_value.Pass());
+  SStringPrintf(&string_conversion_buffer_, "%" PRIx64, value);
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", string_conversion_buffer_);
+  attributes_->EndDictionary();
 }
 
-void MemoryAllocatorDump::AddScalarF(const std::string& name,
+void MemoryAllocatorDump::AddScalarF(const char* name,
                                      const char* units,
                                      double value) {
-  Add(name, kTypeScalar, units, make_scoped_ptr(new FundamentalValue(value)));
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetDouble("value", value);
+  attributes_->EndDictionary();
 }
 
-void MemoryAllocatorDump::AddString(const std::string& name,
+void MemoryAllocatorDump::AddString(const char* name,
                                     const char* units,
                                     const std::string& value) {
-  scoped_ptr<Value> str_value(new StringValue(value));
-  Add(name, kTypeString, units, str_value.Pass());
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeString);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", value);
+  attributes_->EndDictionary();
 }
 
 void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
-  value->BeginDictionary(absolute_name_.c_str());
+  value->BeginDictionaryWithCopiedName(absolute_name_);
   value->SetString("guid", guid_.ToString());
-
-  value->BeginDictionary("attrs");
-
-  for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
-    value->SetValue(it.key().c_str(), it.value().CreateDeepCopy());
-
-  value->EndDictionary();  // "attrs": { ... }
+  value->SetValue("attrs", *attributes_);
   value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
 }
 
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index 9a151a6..2ded173 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -5,9 +5,12 @@
 #ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
 #define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
 
+#include <string>
+
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "base/trace_event/memory_allocator_dump_guid.h"
 #include "base/values.h"
 
@@ -29,45 +32,32 @@
                       ProcessMemoryDump* process_memory_dump);
   ~MemoryAllocatorDump();
 
-  // Standard attribute name to model allocated space.
-  static const char kNameSize[];
+  // Standard attribute |name|s for the AddScalar and AddString() methods.
+  static const char kNameSize[];          // To represent allocated space.
+  static const char kNameObjectsCount[];  // To represent number of objects.
 
-  // Standard attribute name to model total space requested by the allocator
-  // (e.g., amount of pages requested to the system).
-  static const char kNameOuterSize[];
-
-  // Standard attribute name to model space for allocated objects, without
-  // taking into account allocator metadata or fragmentation.
-  static const char kNameInnerSize[];
-
-  // Standard attribute name to model the number of objects allocated.
-  static const char kNameObjectsCount[];
-
-  static const char kTypeScalar[];    // Type name for scalar attributes.
-  static const char kTypeString[];    // Type name for string attributes.
+  // Standard attribute |unit|s for the AddScalar and AddString() methods.
   static const char kUnitsBytes[];    // Unit name to represent bytes.
   static const char kUnitsObjects[];  // Unit name to represent #objects.
 
+  // Constants used only internally and by tests.
+  static const char kTypeScalar[];  // Type name for scalar attributes.
+  static const char kTypeString[];  // Type name for string attributes.
+
+  // Setters for scalar attributes. Some examples:
+  // - "size" column (all dumps are expected to have at least this one):
+  //     AddScalar(kNameSize, kUnitsBytes, 1234);
+  // - Some extra-column reporting internal details of the subsystem:
+  //    AddScalar("number_of_freelist_entires", kUnitsObjects, 42)
+  // - Other informational column (will not be auto-added in the UI)
+  //    AddScalarF("kittens_ratio", "ratio", 42.0f)
+  void AddScalar(const char* name, const char* units, uint64 value);
+  void AddScalarF(const char* name, const char* units, double value);
+  void AddString(const char* name, const char* units, const std::string& value);
+
   // Absolute name, unique within the scope of an entire ProcessMemoryDump.
   const std::string& absolute_name() const { return absolute_name_; }
 
-  // Generic attribute setter / getter.
-  void Add(const std::string& name,
-           const char* type,
-           const char* units,
-           scoped_ptr<Value> value);
-  bool Get(const std::string& name,
-           const char** out_type,
-           const char** out_units,
-           const Value** out_value) const;
-
-  // Helper setter for scalar attributes.
-  void AddScalar(const std::string& name, const char* units, uint64 value);
-  void AddScalarF(const std::string& name, const char* units, double value);
-  void AddString(const std::string& name,
-                 const char* units,
-                 const std::string& value);
-
   // Called at trace generation time to populate the TracedValue.
   void AsValueInto(TracedValue* value) const;
 
@@ -84,12 +74,18 @@
   // expected to have the same guid.
   const MemoryAllocatorDumpGuid& guid() const { return guid_; }
 
+  TracedValue* attributes_for_testing() const { return attributes_.get(); }
+
  private:
   const std::string absolute_name_;
   ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
-  DictionaryValue attributes_;
+  scoped_refptr<TracedValue> attributes_;
   MemoryAllocatorDumpGuid guid_;
 
+  // A local buffer for Sprintf conversion on fastpath. Avoids allocating
+  // temporary strings on each AddScalar() call.
+  std::string string_conversion_buffer_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
 };
 
diff --git a/base/trace_event/memory_allocator_dump_guid.cc b/base/trace_event/memory_allocator_dump_guid.cc
index a4ea50d..69c7de6 100644
--- a/base/trace_event/memory_allocator_dump_guid.cc
+++ b/base/trace_event/memory_allocator_dump_guid.cc
@@ -5,12 +5,21 @@
 #include "base/trace_event/memory_allocator_dump_guid.h"
 
 #include "base/format_macros.h"
-#include "base/hash.h"
+#include "base/sha1.h"
 #include "base/strings/stringprintf.h"
 
 namespace base {
 namespace trace_event {
 
+namespace {
+uint64 HashString(const std::string& str) {
+  uint64 hash[(kSHA1Length + sizeof(uint64) - 1) / sizeof(uint64)] = {0};
+  SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
+                reinterpret_cast<unsigned char*>(hash));
+  return hash[0];
+}
+}  // namespace
+
 MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64 guid) : guid_(guid) {
 }
 
@@ -19,8 +28,7 @@
 }
 
 MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(const std::string& guid_str)
-    : MemoryAllocatorDumpGuid(Hash(guid_str)) {
-}
+    : MemoryAllocatorDumpGuid(HashString(guid_str)) {}
 
 std::string MemoryAllocatorDumpGuid::ToString() const {
   return StringPrintf("%" PRIx64, guid_);
diff --git a/base/trace_event/memory_allocator_dump_guid.h b/base/trace_event/memory_allocator_dump_guid.h
index 84c12ef..634ca81 100644
--- a/base/trace_event/memory_allocator_dump_guid.h
+++ b/base/trace_event/memory_allocator_dump_guid.h
@@ -23,6 +23,8 @@
   // global scope of all the traced processes.
   explicit MemoryAllocatorDumpGuid(const std::string& guid_str);
 
+  uint64 ToUint64() const { return guid_; }
+
   // Returns a (hex-encoded) string representation of the guid.
   std::string ToString() const;
 
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index b9adbae..85b98d6 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -11,6 +11,7 @@
 #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 "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -47,20 +48,23 @@
   }
 };
 
-bool CheckAttribute(const MemoryAllocatorDump* dump,
-                    const std::string& name,
-                    const char* expected_type,
-                    const char* expected_units,
-                    const Value** out_value) {
-  const char* attr_type;
-  const char* attr_units;
-  bool res = dump->Get(name, &attr_type, &attr_units, out_value);
-  EXPECT_TRUE(res);
-  if (!res)
-    return false;
-  EXPECT_EQ(expected_type, std::string(attr_type));
-  EXPECT_EQ(expected_units, std::string(attr_units));
-  return true;
+scoped_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump,
+                                 const std::string& name,
+                                 const char* expected_type,
+                                 const char* expected_units) {
+  scoped_ptr<Value> raw_attrs = dump->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* args = nullptr;
+  DictionaryValue* arg = nullptr;
+  std::string arg_value;
+  const Value* out_value = nullptr;
+  EXPECT_TRUE(raw_attrs->GetAsDictionary(&args));
+  EXPECT_TRUE(args->GetDictionary(name, &arg));
+  EXPECT_TRUE(arg->GetString("type", &arg_value));
+  EXPECT_EQ(expected_type, arg_value);
+  EXPECT_TRUE(arg->GetString("units", &arg_value));
+  EXPECT_EQ(expected_units, arg_value);
+  EXPECT_TRUE(arg->Get("value", &out_value));
+  return out_value ? out_value->CreateDeepCopy() : scoped_ptr<Value>();
 }
 
 void CheckString(const MemoryAllocatorDump* dump,
@@ -68,12 +72,8 @@
                  const char* expected_type,
                  const char* expected_units,
                  const std::string& expected_value) {
-  const Value* attr_value = nullptr;
   std::string attr_str_value;
-  bool res =
-      CheckAttribute(dump, name, expected_type, expected_units, &attr_value);
-  if (!res)
-    return;
+  auto attr_value = CheckAttribute(dump, name, expected_type, expected_units);
   EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
   EXPECT_EQ(expected_value, attr_str_value);
 }
@@ -90,12 +90,9 @@
                   const std::string& name,
                   const char* expected_units,
                   double expected_value) {
-  const Value* attr_value = nullptr;
+  auto attr_value = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
+                                   expected_units);
   double attr_double_value;
-  bool res = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
-                            expected_units, &attr_value);
-  if (!res)
-    return;
   EXPECT_TRUE(attr_value->GetAsDouble(&attr_double_value));
   EXPECT_EQ(expected_value, attr_double_value);
 }
@@ -154,15 +151,15 @@
               MemoryAllocatorDump::kUnitsBytes, 1);
   CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
               MemoryAllocatorDump::kUnitsObjects, 3);
-
   const MemoryAllocatorDump* empty_sub_heap =
       pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
   ASSERT_NE(nullptr, empty_sub_heap);
   EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
-  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameSize, nullptr,
-                                   nullptr, nullptr));
-  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameObjectsCount,
-                                   nullptr, nullptr, nullptr));
+  auto raw_attrs = empty_sub_heap->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* attrs = nullptr;
+  ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectsCount));
 
   // Check that the AsValueInfo doesn't hit any DCHECK.
   scoped_refptr<TracedValue> traced_value(new TracedValue());
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 15abb91..e2ca702 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -8,6 +8,8 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/compiler_specific.h"
+#include "base/hash.h"
+#include "base/thread_task_runner_handle.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"
@@ -40,96 +42,26 @@
 // trace event synthetic delays.
 const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("memory-infra");
 
-MemoryDumpManager* g_instance_for_testing = nullptr;
-const int kDumpIntervalSeconds = 2;
+// Throttle mmaps at a rate of once every kHeavyMmapsDumpsRate standard dumps.
+const int kHeavyMmapsDumpsRate = 8;  // 250 ms * 8 = 2000 ms.
+const int kDumpIntervalMs = 250;
 const int kTraceEventNumArgs = 1;
 const char* kTraceEventArgNames[] = {"dumps"};
 const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+
 StaticAtomicSequenceNumber g_next_guid;
-
-const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
-  switch (dump_type) {
-    case MemoryDumpType::TASK_BEGIN:
-      return "TASK_BEGIN";
-    case MemoryDumpType::TASK_END:
-      return "TASK_END";
-    case MemoryDumpType::PERIODIC_INTERVAL:
-      return "PERIODIC_INTERVAL";
-    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();
-  }
-}
+uint32 g_periodic_dumps_count = 0;
+MemoryDumpManager* g_instance_for_testing = nullptr;
+MemoryDumpProvider* g_mmaps_dump_provider = nullptr;
 
 void RequestPeriodicGlobalDump() {
-  MemoryDumpManager::GetInstance()->RequestGlobalDump(
-      MemoryDumpType::PERIODIC_INTERVAL);
+  MemoryDumpType dump_type = g_periodic_dumps_count == 0
+                                 ? MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS
+                                 : MemoryDumpType::PERIODIC_INTERVAL;
+  if (++g_periodic_dumps_count == kHeavyMmapsDumpsRate)
+    g_periodic_dumps_count = 0;
+
+  MemoryDumpManager::GetInstance()->RequestGlobalDump(dump_type);
 }
 
 }  // namespace
@@ -138,6 +70,12 @@
 const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
 
 // static
+const uint64 MemoryDumpManager::kInvalidTracingProcessId = 0;
+
+// static
+const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
+
+// static
 MemoryDumpManager* MemoryDumpManager::GetInstance() {
   if (g_instance_for_testing)
     return g_instance_for_testing;
@@ -154,8 +92,10 @@
 }
 
 MemoryDumpManager::MemoryDumpManager()
-    : delegate_(nullptr),
+    : did_unregister_dump_provider_(false),
+      delegate_(nullptr),
       memory_tracing_enabled_(0),
+      tracing_process_id_(kInvalidTracingProcessId),
       skip_core_dumpers_auto_registration_for_testing_(false) {
   g_next_guid.GetNext();  // Make sure that first guid is not zero.
 }
@@ -177,7 +117,8 @@
 #endif
 
 #if (defined(OS_LINUX) && !defined(FNL_MUSL)) || defined(OS_ANDROID)
-  RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
+  g_mmaps_dump_provider = ProcessMemoryMapsDumpProvider::GetInstance();
+  RegisterDumpProvider(g_mmaps_dump_provider);
   RegisterDumpProvider(MallocDumpProvider::GetInstance());
 #endif
 
@@ -199,9 +140,9 @@
 void MemoryDumpManager::RegisterDumpProvider(
     MemoryDumpProvider* mdp,
     const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
-  MemoryDumpProviderInfo mdp_info(task_runner);
+  MemoryDumpProviderInfo mdp_info(mdp, task_runner);
   AutoLock lock(lock_);
-  dump_providers_.insert(std::make_pair(mdp, mdp_info));
+  dump_providers_.insert(mdp_info);
 }
 
 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
@@ -211,11 +152,15 @@
 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
   AutoLock lock(lock_);
 
-  auto it = dump_providers_.find(mdp);
-  if (it == dump_providers_.end())
+  auto mdp_iter = dump_providers_.begin();
+  for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
+    if (mdp_iter->dump_provider == mdp)
+      break;
+  }
+
+  if (mdp_iter == dump_providers_.end())
     return;
 
-  const MemoryDumpProviderInfo& mdp_info = it->second;
   // 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
@@ -224,13 +169,12 @@
   // race-free. If you hit this DCHECK, your MDP has a bug.
   DCHECK_IMPLIES(
       subtle::NoBarrier_Load(&memory_tracing_enabled_),
-      mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
+      mdp_iter->task_runner && mdp_iter->task_runner->BelongsToCurrentThread())
       << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
-      << " Please file a crbug.";
+      << "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.
-  dump_providers_.erase(it);
+  dump_providers_.erase(mdp_iter);
+  did_unregister_dump_provider_ = true;
 }
 
 void MemoryDumpManager::RequestGlobalDump(
@@ -265,96 +209,179 @@
   RequestGlobalDump(dump_type, MemoryDumpCallback());
 }
 
-// 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 OnMemoryDump(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.OnMemoryDump() 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 OnMemoryDump() 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.
+  scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
   {
     AutoLock lock(lock_);
-    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
-      MemoryDumpProvider* mdp = it->first;
-      MemoryDumpProviderInfo* mdp_info = &it->second;
-      if (mdp_info->disabled)
-        continue;
-      if (mdp_info->task_runner) {
-        // The OnMemoryDump() call must be posted.
-        bool did_post_async_task = mdp_info->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.OnMemoryDump(), taking care of the fail-safe
-// logic which disables the dumper when failing (crbug.com/461788).
-bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
-                                                 ProcessMemoryDump* pmd) {
-  lock_.AssertAcquired();
-  bool dump_successful = mdp->OnMemoryDump(pmd);
-  if (!dump_successful) {
-    LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
-                  "(crbug.com/461788), disabling it for current process. Try "
-                  "restarting chrome with the --no-sandbox switch.";
-    dump_providers_.find(mdp)->second.disabled = true;
+    did_unregister_dump_provider_ = false;
+    pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
+        args, dump_providers_.begin(), session_state_, callback));
   }
-  return dump_successful;
+
+  // Start the thread hop. |dump_providers_| are kept sorted by thread, so
+  // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
+  // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
+  ContinueAsyncProcessDump(pmd_async_state.Pass());
 }
 
-// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
-// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
-// happen on a different thread.
+// At most one ContinueAsyncProcessDump() can be active at any time for a given
+// PMD, regardless of status of the |lock_|. |lock_| is used here purely to
+// ensure consistency w.r.t. (un)registrations of |dump_providers_|.
+// The linearization of dump providers' OnMemoryDump invocations is achieved by
+// means of subsequent PostTask(s).
+//
+// 1) Prologue:
+//   - Check if the dump provider is disabled, if so skip the dump.
+//   - Check if we are on the right thread. If not hop and continue there.
+// 2) Invoke the dump provider's OnMemoryDump() (unless skipped).
+// 3) Epilogue:
+//  - Unregister the dump provider if it failed too many times consecutively.
+//  - Advance the |next_dump_provider| iterator to the next dump provider.
+//  - If this was the last hop, create a trace event, add it to the trace
+//    and finalize (invoke callback).
+
 void MemoryDumpManager::ContinueAsyncProcessDump(
-    MemoryDumpProvider* mdp,
-    scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
-  bool should_finalize_dump = false;
+    scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+  // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
+  // in the PostTask below don't end up registering their own dump providers
+  // (for discounting trace memory overhead) while holding the |lock_|.
+  TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
+  // DO NOT put any LOG() statement in the locked sections, as in some contexts
+  // (GPU process) LOG() ends up performing PostTask/IPCs.
+  MemoryDumpProvider* mdp;
+  bool skip_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;
+    // In the unlikely event that a dump provider was unregistered while
+    // dumping, abort the dump, as that would make |next_dump_provider| invalid.
+    // Registration, on the other hand, is safe as per std::set<> contract.
+    if (did_unregister_dump_provider_) {
+      return AbortDumpLocked(pmd_async_state->callback,
+                             pmd_async_state->task_runner,
+                             pmd_async_state->req_args.dump_guid);
+    }
 
-    // Check if the MemoryDumpProvider is still there. It might have been
-    // destroyed and unregistered while hopping threads.
-    if (dump_providers_.count(mdp))
-      InvokeDumpProviderLocked(mdp, pmd);
+    auto* mdp_info = &*pmd_async_state->next_dump_provider;
+    mdp = mdp_info->dump_provider;
+    if (mdp_info->disabled) {
+      skip_dump = true;
+    } else if (mdp == g_mmaps_dump_provider &&
+               pmd_async_state->req_args.dump_type !=
+                   MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS) {
+      // Mmaps dumping is very heavyweight and cannot be performed at the same
+      // rate of other dumps. TODO(primiano): this is a hack and should be
+      // cleaned up as part of crbug.com/499731.
+      skip_dump = true;
+    } else if (mdp_info->task_runner &&
+               !mdp_info->task_runner->BelongsToCurrentThread()) {
+      // It's time to hop onto another thread.
 
-    // 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;
+      // Copy the callback + arguments just for the unlikley case in which
+      // PostTask fails. In such case the Bind helper will destroy the
+      // pmd_async_state and we must keep a copy of the fields to notify the
+      // abort.
+      MemoryDumpCallback callback = pmd_async_state->callback;
+      scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+          pmd_async_state->task_runner;
+      const uint64 dump_guid = pmd_async_state->req_args.dump_guid;
+
+      const bool did_post_task = mdp_info->task_runner->PostTask(
+          FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+                          Unretained(this), Passed(pmd_async_state.Pass())));
+      if (did_post_task)
+        return;
+
+      // The thread is gone. At this point the best thing we can do is to
+      // disable the dump provider and abort this dump.
+      mdp_info->disabled = true;
+      return AbortDumpLocked(callback, callback_task_runner, dump_guid);
+    }
   }  // AutoLock(lock_)
 
-  if (should_finalize_dump)
-    FinalizeDumpAndAddToTrace(pmd_holder);
+  // Invoke the dump provider without holding the |lock_|.
+  bool finalize = false;
+  bool dump_successful = false;
+  if (!skip_dump)
+    dump_successful = mdp->OnMemoryDump(&pmd_async_state->process_memory_dump);
+
+  {
+    AutoLock lock(lock_);
+    if (did_unregister_dump_provider_) {
+      return AbortDumpLocked(pmd_async_state->callback,
+                             pmd_async_state->task_runner,
+                             pmd_async_state->req_args.dump_guid);
+    }
+    auto* mdp_info = &*pmd_async_state->next_dump_provider;
+    if (dump_successful) {
+      mdp_info->consecutive_failures = 0;
+    } else if (!skip_dump) {
+      ++mdp_info->consecutive_failures;
+      if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+        mdp_info->disabled = true;
+      }
+    }
+    ++pmd_async_state->next_dump_provider;
+    finalize = pmd_async_state->next_dump_provider == dump_providers_.end();
+  }
+
+  if (!skip_dump && !dump_successful) {
+    LOG(ERROR) << "A memory dumper failed, possibly due to sandboxing "
+                  "(crbug.com/461788). Disabling dumper for current process. "
+                  "Try restarting chrome with the --no-sandbox switch.";
+  }
+
+  if (finalize)
+    return FinalizeDumpAndAddToTrace(pmd_async_state.Pass());
+
+  ContinueAsyncProcessDump(pmd_async_state.Pass());
+}
+
+// static
+void MemoryDumpManager::FinalizeDumpAndAddToTrace(
+    scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+  if (!pmd_async_state->task_runner->BelongsToCurrentThread()) {
+    scoped_refptr<SingleThreadTaskRunner> task_runner =
+        pmd_async_state->task_runner;
+    task_runner->PostTask(FROM_HERE,
+                          Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
+                               Passed(pmd_async_state.Pass())));
+    return;
+  }
+
+  scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
+  pmd_async_state->process_memory_dump.AsValueInto(
+      static_cast<TracedValue*>(event_value.get()));
+  const char* const event_name =
+      MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
+
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      TRACE_EVENT_PHASE_MEMORY_DUMP,
+      TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+      pmd_async_state->req_args.dump_guid, kTraceEventNumArgs,
+      kTraceEventArgNames, kTraceEventArgTypes, nullptr /* arg_values */,
+      &event_value, TRACE_EVENT_FLAG_HAS_ID);
+
+  if (!pmd_async_state->callback.is_null()) {
+    pmd_async_state->callback.Run(pmd_async_state->req_args.dump_guid,
+                                  true /* success */);
+    pmd_async_state->callback.Reset();
+  }
+}
+
+// static
+void MemoryDumpManager::AbortDumpLocked(
+    MemoryDumpCallback callback,
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
+    uint64 dump_guid) {
+  if (callback.is_null())
+    return;  // There is nothing to NACK.
+
+  // Post the callback even if we are already on the right thread to avoid
+  // invoking the callback while holding the lock_.
+  task_runner->PostTask(FROM_HERE,
+                        Bind(callback, dump_guid, false /* success */));
 }
 
 void MemoryDumpManager::OnTraceLogEnabled() {
@@ -364,25 +391,33 @@
   bool enabled;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
 
+  // Initialize the TraceLog for the current thread. This is to avoid that the
+  // TraceLog memory dump provider is registered lazily in the PostTask() below
+  // while the |lock_| is taken;
+  TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
   AutoLock lock(lock_);
 
   // There is no point starting the tracing without a delegate.
   if (!enabled || !delegate_) {
     // Disable all the providers.
     for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
-      it->second.disabled = true;
+      it->disabled = true;
     return;
   }
 
   session_state_ = new MemoryDumpSessionState();
-  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
-    it->second.disabled = false;
+  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+    it->disabled = false;
+    it->consecutive_failures = 0;
+  }
 
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
 
   if (delegate_->IsCoordinatorProcess()) {
+    g_periodic_dumps_count = 0;
     periodic_dump_timer_.Start(FROM_HERE,
-                               TimeDelta::FromSeconds(kDumpIntervalSeconds),
+                               TimeDelta::FromMilliseconds(kDumpIntervalMs),
                                base::Bind(&RequestPeriodicGlobalDump));
   }
 }
@@ -394,12 +429,46 @@
   session_state_ = nullptr;
 }
 
-MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
-    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
-    : task_runner(task_runner), disabled(false) {
+// static
+uint64 MemoryDumpManager::ChildProcessIdToTracingProcessId(
+    int child_process_id) {
+  return static_cast<uint64>(
+             Hash(reinterpret_cast<const char*>(&child_process_id),
+                  sizeof(child_process_id))) +
+         1;
 }
+
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+    MemoryDumpProvider* dump_provider,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : dump_provider(dump_provider),
+      task_runner(task_runner),
+      consecutive_failures(0),
+      disabled(false) {}
+
 MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
 }
 
+bool MemoryDumpManager::MemoryDumpProviderInfo::operator<(
+    const MemoryDumpProviderInfo& other) const {
+  if (task_runner == other.task_runner)
+    return dump_provider < other.dump_provider;
+  return task_runner < other.task_runner;
+}
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
+    MemoryDumpRequestArgs req_args,
+    MemoryDumpProviderInfoSet::iterator next_dump_provider,
+    const scoped_refptr<MemoryDumpSessionState>& session_state,
+    MemoryDumpCallback callback)
+    : process_memory_dump(session_state),
+      req_args(req_args),
+      next_dump_provider(next_dump_provider),
+      callback(callback),
+      task_runner(MessageLoop::current()->task_runner()) {}
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 3645ac1..f9ece6e 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -5,7 +5,7 @@
 #ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
 #define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
 
-#include <vector>
+#include <set>
 
 #include "base/atomicops.h"
 #include "base/containers/hash_tables.h"
@@ -14,6 +14,7 @@
 #include "base/synchronization/lock.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 
 namespace base {
@@ -22,13 +23,8 @@
 
 namespace trace_event {
 
-namespace {
-class ProcessMemoryDumpHolder;
-}
-
 class MemoryDumpManagerDelegate;
 class MemoryDumpProvider;
-class ProcessMemoryDump;
 class MemoryDumpSessionState;
 
 // This is the interface exposed to the rest of the codebase to deal with
@@ -36,6 +32,7 @@
 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
 class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
  public:
+  static const uint64 kInvalidTracingProcessId;
   static const char* const kTraceCategoryForTesting;
 
   static MemoryDumpManager* GetInstance();
@@ -81,27 +78,97 @@
     return session_state_;
   }
 
+  // Derives a tracing process id from a child process id. Child process ids
+  // cannot be used directly in tracing for security reasons (see: discussion in
+  // crrev.com/1173263004). This method is meant to be used when dumping
+  // cross-process shared memory from a process which knows the child process id
+  // of its endpoints. The value returned by this method is guaranteed to be
+  // equal to the value returned by tracing_process_id() in the corresponding
+  // child process.
+  // This will never return kInvalidTracingProcessId.
+  static uint64 ChildProcessIdToTracingProcessId(int child_id);
+
+  // Returns a unique id for the current process. The id can be retrieved only
+  // by child processes and only when tracing is enabled. This is intended to
+  // express cross-process sharing of memory dumps on the child-process side,
+  // without having to know its own child process id.
+  uint64 tracing_process_id() const { return tracing_process_id_; }
+
  private:
-  // Descriptor struct used to hold information about registered MDPs. It is
-  // deliberately copyable, in order to allow to be used as hash_map value.
-  struct MemoryDumpProviderInfo {
-    MemoryDumpProviderInfo(
-        const scoped_refptr<SingleThreadTaskRunner>& task_runner);
-    ~MemoryDumpProviderInfo();
-
-    scoped_refptr<SingleThreadTaskRunner> task_runner;  // Optional.
-    bool disabled;  // For fail-safe logic (auto-disable failing MDPs).
-  };
-
   friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
   friend struct DefaultSingletonTraits<MemoryDumpManager>;
   friend class MemoryDumpManagerDelegate;
   friend class MemoryDumpManagerTest;
+  FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, DisableFailingDumpers);
 
-  static void SetInstanceForTesting(MemoryDumpManager* instance);
+  // Descriptor struct used to hold information about registered MDPs. It is
+  // deliberately copyable, in order to allow it to be used as std::set value.
+  struct MemoryDumpProviderInfo {
+    MemoryDumpProviderInfo(
+        MemoryDumpProvider* dump_provider,
+        const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+    ~MemoryDumpProviderInfo();
+
+    // Define a total order based on the thread (i.e. |task_runner|) affinity,
+    // so that all MDP belonging to the same thread are adjacent in the set.
+    bool operator<(const MemoryDumpProviderInfo& other) const;
+
+    MemoryDumpProvider* const dump_provider;
+    scoped_refptr<SingleThreadTaskRunner> task_runner;  // Optional.
+
+    // For fail-safe logic (auto-disable failing MDPs). These fields are mutable
+    // as can be safely changed without impacting the order within the set.
+    mutable int consecutive_failures;
+    mutable bool disabled;
+  };
+
+  using MemoryDumpProviderInfoSet = std::set<MemoryDumpProviderInfo>;
+
+  // Holds the state of a process memory dump that needs to be carried over
+  // across threads in order to fulfil an asynchronous CreateProcessDump()
+  // request. At any time exactly one thread owns a ProcessMemoryDumpAsyncState.
+  struct ProcessMemoryDumpAsyncState {
+    ProcessMemoryDumpAsyncState(
+        MemoryDumpRequestArgs req_args,
+        MemoryDumpProviderInfoSet::iterator next_dump_provider,
+        const scoped_refptr<MemoryDumpSessionState>& session_state,
+        MemoryDumpCallback callback);
+    ~ProcessMemoryDumpAsyncState();
+
+    // The ProcessMemoryDump container, where each dump provider will dump its
+    // own MemoryAllocatorDump(s) upon the OnMemoryDump() call.
+    ProcessMemoryDump process_memory_dump;
+
+    // The arguments passed to the initial CreateProcessDump() request.
+    const MemoryDumpRequestArgs req_args;
+
+    // The |dump_providers_| iterator to the next dump provider that should be
+    // invoked (or dump_providers_.end() if at the end of the sequence).
+    MemoryDumpProviderInfoSet::iterator next_dump_provider;
+
+    // Callback passed to the initial call to CreateProcessDump().
+    MemoryDumpCallback callback;
+
+    // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
+    // should be invoked. This is the thread on which the initial
+    // CreateProcessDump() request was called.
+    const scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
+  };
+
+  static const int kMaxConsecutiveFailuresCount;
 
   MemoryDumpManager();
-  virtual ~MemoryDumpManager();
+  ~MemoryDumpManager() override;
+
+  static void SetInstanceForTesting(MemoryDumpManager* instance);
+  static void FinalizeDumpAndAddToTrace(
+      scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+  static void AbortDumpLocked(MemoryDumpCallback callback,
+                              scoped_refptr<SingleThreadTaskRunner> task_runner,
+                              uint64 dump_guid);
 
   // Internal, used only by MemoryDumpManagerDelegate.
   // Creates a memory dump for the current process and appends it to the trace.
@@ -110,13 +177,25 @@
   void CreateProcessDump(const MemoryDumpRequestArgs& args,
                          const MemoryDumpCallback& callback);
 
-  bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
-                                ProcessMemoryDump* pmd);
+  // Continues the ProcessMemoryDump started by CreateProcessDump(), hopping
+  // across threads as needed as specified by MDPs in RegisterDumpProvider().
   void ContinueAsyncProcessDump(
-      MemoryDumpProvider* mdp,
-      scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
+      scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
 
-  hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
+  // Pass kInvalidTracingProcessId to invalidate the id.
+  void set_tracing_process_id(uint64 id) {
+    DCHECK(tracing_process_id_ == kInvalidTracingProcessId ||
+           id == kInvalidTracingProcessId || tracing_process_id_ == id);
+    tracing_process_id_ = id;
+  }
+
+  // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread
+  // affinity (MDPs belonging to the same thread are adjacent).
+  MemoryDumpProviderInfoSet dump_providers_;
+
+  // Flag used to signal that some provider was removed from |dump_providers_|
+  // and therefore the current memory dump (if any) should be aborted.
+  bool did_unregister_dump_provider_;
 
   // Shared among all the PMDs to keep state scoped to the tracing session.
   scoped_refptr<MemoryDumpSessionState> session_state_;
@@ -134,6 +213,10 @@
   // For time-triggered periodic dumps.
   RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
 
+  // The unique id of the child process. This is created only for tracing and is
+  // expected to be valid only when tracing is enabled.
+  uint64 tracing_process_id_;
+
   // Skips the auto-registration of the core dumpers during Initialize().
   bool skip_core_dumpers_auto_registration_for_testing_;
 
@@ -160,6 +243,10 @@
     MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
   }
 
+  void set_tracing_process_id(uint64 id) {
+    MemoryDumpManager::GetInstance()->set_tracing_process_id(id);
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
 };
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index c15748c..be20cec 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
@@ -15,6 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::Between;
 using testing::Invoke;
 using testing::Return;
 
@@ -25,9 +27,8 @@
 // instead of performing IPC dances.
 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
  public:
-  void RequestGlobalMemoryDump(
-      const base::trace_event::MemoryDumpRequestArgs& args,
-      const MemoryDumpCallback& callback) override {
+  void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
+                               const MemoryDumpCallback& callback) override {
     CreateProcessDump(args, callback);
   }
 
@@ -81,7 +82,9 @@
 
 class MockDumpProvider : public MemoryDumpProvider {
  public:
-  MockDumpProvider() : last_session_state_(nullptr) {}
+  MockDumpProvider()
+      : dump_provider_to_register_or_unregister(nullptr),
+        last_session_state_(nullptr) {}
 
   // Ctor used by the RespectTaskRunnerAffinity test.
   explicit MockDumpProvider(
@@ -107,6 +110,23 @@
     return true;
   }
 
+  // OnMemoryDump() override for the RegisterDumperWhileDumping test.
+  bool OnMemoryDump_RegisterExtraDumpProvider(ProcessMemoryDump* pmd) {
+    MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+        dump_provider_to_register_or_unregister);
+    return true;
+  }
+
+  // OnMemoryDump() override for the UnegisterDumperWhileDumping test.
+  bool OnMemoryDump_UnregisterDumpProvider(ProcessMemoryDump* pmd) {
+    MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+        dump_provider_to_register_or_unregister);
+    return true;
+  }
+
+  // Used by OnMemoryDump_(Un)RegisterExtraDumpProvider.
+  MemoryDumpProvider* dump_provider_to_register_or_unregister;
+
  private:
   MemoryDumpSessionState* last_session_state_;
   scoped_refptr<SingleThreadTaskRunner> task_runner_;
@@ -250,9 +270,8 @@
   DisableTracing();
 }
 
-// Enable both dump providers, make mdp1 fail and assert that only mdp2 is
-// invoked the 2nd time.
-// FIXME(primiano): remove once crbug.com/461788 gets fixed.
+// Enable both dump providers, make sure that mdp gets disabled after 3 failures
+// and not disabled after 1.
 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
   MockDumpProvider mdp1;
   MockDumpProvider mdp2;
@@ -261,13 +280,78 @@
   mdm_->RegisterDumpProvider(&mdp2);
   EnableTracing(kTraceCategory);
 
-  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
-  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
-  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  EXPECT_CALL(mdp1, OnMemoryDump(_))
+      .Times(MemoryDumpManager::kMaxConsecutiveFailuresCount)
+      .WillRepeatedly(Return(false));
 
-  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
-  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
-  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .Times(1 + MemoryDumpManager::kMaxConsecutiveFailuresCount)
+      .WillOnce(Return(false))
+      .WillRepeatedly(Return(true));
+  for (int i = 0; i < 1 + MemoryDumpManager::kMaxConsecutiveFailuresCount;
+       i++) {
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  }
+
+  DisableTracing();
+}
+
+// Sneakily register an extra memory dump provider while an existing one is
+// dumping and expect it to take part in the already active tracing session.
+TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+
+  mdp1.dump_provider_to_register_or_unregister = &mdp2;
+  mdm_->RegisterDumpProvider(&mdp1);
+  EnableTracing(kTraceCategory);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_))
+      .Times(4)
+      .WillOnce(Return(true))
+      .WillOnce(Invoke(
+          &mdp1, &MockDumpProvider::OnMemoryDump_RegisterExtraDumpProvider))
+      .WillRepeatedly(Return(true));
+
+  // Depending on the insertion order (before or after mdp1), mdp2 might be
+  // called also immediately after it gets registered.
+  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .Times(Between(2, 3))
+      .WillRepeatedly(Return(true));
+
+  for (int i = 0; i < 4; i++) {
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  }
+
+  DisableTracing();
+}
+
+// Like the above, but suddenly unregister the dump provider.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+
+  mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
+  mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
+  mdp1.dump_provider_to_register_or_unregister = &mdp2;
+  EnableTracing(kTraceCategory);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_))
+      .Times(4)
+      .WillOnce(Return(true))
+      .WillOnce(
+          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_UnregisterDumpProvider))
+      .WillRepeatedly(Return(true));
+
+  // Depending on the insertion order (before or after mdp1), mdp2 might have
+  // been already called when OnMemoryDump_UnregisterDumpProvider happens.
+  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .Times(Between(1, 2))
+      .WillRepeatedly(Return(true));
+
+  for (int i = 0; i < 4; i++) {
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  }
 
   DisableTracing();
 }
diff --git a/base/trace_event/memory_dump_request_args.cc b/base/trace_event/memory_dump_request_args.cc
new file mode 100644
index 0000000..196e98c
--- /dev/null
+++ b/base/trace_event/memory_dump_request_args.cc
@@ -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.
+
+#include "base/trace_event/memory_dump_request_args.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+  switch (dump_type) {
+    case MemoryDumpType::TASK_BEGIN:
+      return "TASK_BEGIN";
+    case MemoryDumpType::TASK_END:
+      return "TASK_END";
+    case MemoryDumpType::PERIODIC_INTERVAL:
+      return "PERIODIC_INTERVAL";
+    case MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS:
+      return "PERIODIC_INTERVAL_WITH_MMAPS";
+    case MemoryDumpType::EXPLICITLY_TRIGGERED:
+      return "EXPLICITLY_TRIGGERED";
+  }
+  NOTREACHED();
+  return "UNKNOWN";
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
index 4d3763a..05d98be 100644
--- a/base/trace_event/memory_dump_request_args.h
+++ b/base/trace_event/memory_dump_request_args.h
@@ -20,10 +20,15 @@
   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.
+  PERIODIC_INTERVAL_WITH_MMAPS,  // As above but w/ heavyweight mmaps dumps.
+                                 // Temporary workaround for crbug.com/499731.
+  EXPLICITLY_TRIGGERED,          // Non maskable dump request.
+  LAST = EXPLICITLY_TRIGGERED    // For IPC macros.
 };
 
+// Returns the name in string for the dump type given.
+BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
+
 using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
 
 struct BASE_EXPORT MemoryDumpRequestArgs {
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index 88ce28a..3b71a2c 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -48,29 +48,6 @@
   ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
   ~ProcessMemoryDump();
 
-  // Called at trace generation time to populate the TracedValue.
-  void AsValueInto(TracedValue* value) const;
-
-  // Removes all the MemoryAllocatorDump(s) contained in this instance. This
-  // ProcessMemoryDump can be safely reused as if it was new once this returns.
-  void Clear();
-
-  // Merges all MemoryAllocatorDump(s) contained in |other| inside this
-  // ProcessMemoryDump, transferring their ownership to this instance.
-  // |other| will be an empty ProcessMemoryDump after this method returns.
-  // This is to allow dump providers to pre-populate ProcessMemoryDump instances
-  // and later move their contents into the ProcessMemoryDump passed as argument
-  // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
-  void TakeAllDumpsFrom(ProcessMemoryDump* other);
-
-  ProcessMemoryTotals* process_totals() { return &process_totals_; }
-  bool has_process_totals() const { return has_process_totals_; }
-  void set_has_process_totals() { has_process_totals_ = true; }
-
-  ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
-  bool has_process_mmaps() const { return has_process_mmaps_; }
-  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.
   // Arguments:
@@ -80,7 +57,8 @@
   //       Leading or trailing slashes are not allowed.
   //   guid: an optional identifier, unique among all processes within the
   //       scope of a global dump. This is only relevant when using
-  //       AddOwnershipEdge(). If omitted, it will be automatically generated.
+  //       AddOwnershipEdge() to express memory sharing. If omitted,
+  //       it will be automatically generated.
   // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
   MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
   MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
@@ -131,6 +109,29 @@
     return session_state_;
   }
 
+  // Removes all the MemoryAllocatorDump(s) contained in this instance. This
+  // ProcessMemoryDump can be safely reused as if it was new once this returns.
+  void Clear();
+
+  // Merges all MemoryAllocatorDump(s) contained in |other| inside this
+  // ProcessMemoryDump, transferring their ownership to this instance.
+  // |other| will be an empty ProcessMemoryDump after this method returns.
+  // This is to allow dump providers to pre-populate ProcessMemoryDump instances
+  // and later move their contents into the ProcessMemoryDump passed as argument
+  // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
+  void TakeAllDumpsFrom(ProcessMemoryDump* other);
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  ProcessMemoryTotals* process_totals() { return &process_totals_; }
+  bool has_process_totals() const { return has_process_totals_; }
+  void set_has_process_totals() { has_process_totals_ = true; }
+
+  ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+  bool has_process_mmaps() const { return has_process_mmaps_; }
+  void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
  private:
   void AddAllocatorDumpInternal(MemoryAllocatorDump* mad);
 
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
index ef9b892..2a15ec5 100644
--- a/base/trace_event/trace_config.cc
+++ b/base/trace_event/trace_config.cc
@@ -6,6 +6,7 @@
 
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
+#include "base/strings/pattern.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/stringprintf.h"
@@ -147,8 +148,8 @@
     if (IsCategoryEnabled(category_group_token.c_str())) {
       return true;
     }
-    if (!MatchPattern(category_group_token.c_str(),
-                      TRACE_DISABLED_BY_DEFAULT("*")))
+    if (!base::MatchPattern(category_group_token.c_str(),
+                            TRACE_DISABLED_BY_DEFAULT("*")))
       had_enabled_by_default = true;
   }
   // Do a second pass to check for explicitly disabled categories
@@ -160,7 +161,7 @@
     for (StringList::const_iterator ci = excluded_categories_.begin();
          ci != excluded_categories_.end();
          ++ci) {
-      if (MatchPattern(category_group_token.c_str(), ci->c_str())) {
+      if (base::MatchPattern(category_group_token.c_str(), ci->c_str())) {
         // Current token of category_group_name is present in excluded_list.
         // Flag the exclusion and proceed further to check if any of the
         // remaining categories of category_group_name is not present in the
@@ -515,17 +516,17 @@
   for (ci = disabled_categories_.begin();
        ci != disabled_categories_.end();
        ++ci) {
-    if (MatchPattern(category_name, ci->c_str()))
+    if (base::MatchPattern(category_name, ci->c_str()))
       return true;
   }
 
-  if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
+  if (base::MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
     return false;
 
   for (ci = included_categories_.begin();
        ci != included_categories_.end();
        ++ci) {
-    if (MatchPattern(category_name, ci->c_str()))
+    if (base::MatchPattern(category_name, ci->c_str()))
       return true;
   }
 
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 397bafc..77ec1de 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -852,6 +852,10 @@
 #define TRACE_EVENT_FLOW_END0(category_group, name, id) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(category_group, name, id)      \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id,                                   \
+                                   TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
 #define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
@@ -885,6 +889,14 @@
         category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE,\
         "snapshot", snapshot)
 
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(            \
+    category_group, name, id, timestamp, snapshot)                    \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                 \
+      TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name,        \
+      TRACE_ID_DONT_MANGLE(id),                                       \
+      static_cast<int>(base::PlatformThread::CurrentId()), timestamp, \
+      TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
+
 #define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_DELETE_OBJECT, \
         category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
@@ -954,7 +966,7 @@
 //                    const char** arg_names,
 //                    const unsigned char* arg_types,
 //                    const unsigned long long* arg_values,
-//                    unsigned char flags)
+//                    unsigned int flags)
 #define TRACE_EVENT_API_ADD_TRACE_EVENT \
     base::trace_event::TraceLog::GetInstance()->AddTraceEvent
 
@@ -971,7 +983,7 @@
 //                    const char** arg_names,
 //                    const unsigned char* arg_types,
 //                    const unsigned long long* arg_values,
-//                    unsigned char flags)
+//                    unsigned int flags)
 #define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \
     base::trace_event::TraceLog::GetInstance() \
       ->AddTraceEventWithThreadIdAndTimestamp
@@ -1067,39 +1079,38 @@
 
 // Implementation detail: internal macro to create static category and add
 // event if the category is enabled.
-#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \
-                                         flags, ...) \
-    do { \
-      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
-      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
-        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
-        trace_event_internal::TraceID trace_event_trace_id( \
-            id, &trace_event_flags); \
-        trace_event_internal::AddTraceEvent( \
-            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
-            name, trace_event_trace_id.data(), trace_event_flags, \
-            ##__VA_ARGS__); \
-      } \
-    } while (0)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id,     \
+                                         flags, ...)                          \
+  do {                                                                        \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                   \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {   \
+      unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID;       \
+      trace_event_internal::TraceID trace_event_trace_id(id,                  \
+                                                         &trace_event_flags); \
+      trace_event_internal::AddTraceEvent(                                    \
+          phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,      \
+          trace_event_trace_id.data(), trace_event_flags, ##__VA_ARGS__);     \
+    }                                                                         \
+  } while (0)
 
 // Implementation detail: internal macro to create static category and add
 // event if the category is enabled.
-#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(phase, \
-        category_group, name, id, thread_id, timestamp, flags, ...) \
-    do { \
-      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
-      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
-        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
-        trace_event_internal::TraceID trace_event_trace_id( \
-            id, &trace_event_flags); \
-        trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
-            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
-            name, trace_event_trace_id.data(), \
-            thread_id, base::TraceTicks::FromInternalValue(timestamp), \
-            trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
-            ##__VA_ARGS__); \
-      } \
-    } while (0)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+    phase, category_group, name, id, thread_id, timestamp, flags, ...)        \
+  do {                                                                        \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                   \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {   \
+      unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID;       \
+      trace_event_internal::TraceID trace_event_trace_id(id,                  \
+                                                         &trace_event_flags); \
+      trace_event_internal::AddTraceEventWithThreadIdAndTimestamp(            \
+          phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,      \
+          trace_event_trace_id.data(), thread_id,                             \
+          base::TraceTicks::FromInternalValue(timestamp),                     \
+          trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP,            \
+          ##__VA_ARGS__);                                                     \
+    }                                                                         \
+  } while (0)
 
 // Notes regarding the following definitions:
 // New values can be added and propagated to third party libraries, but existing
@@ -1130,17 +1141,19 @@
 #define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
 
 // Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
-#define TRACE_EVENT_FLAG_NONE         (static_cast<unsigned char>(0))
-#define TRACE_EVENT_FLAG_COPY         (static_cast<unsigned char>(1 << 0))
-#define TRACE_EVENT_FLAG_HAS_ID       (static_cast<unsigned char>(1 << 1))
-#define TRACE_EVENT_FLAG_MANGLE_ID    (static_cast<unsigned char>(1 << 2))
-#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
-#define TRACE_EVENT_FLAG_SCOPE_EXTRA  (static_cast<unsigned char>(1 << 4))
-#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
-#define TRACE_EVENT_FLAG_ASYNC_TTS    (static_cast<unsigned char>(1 << 6))
+#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
+#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned int>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned int>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned int>(1 << 2))
+#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned int>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned int>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned int>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned int>(1 << 6))
+#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned int>(1 << 7))
 
-#define TRACE_EVENT_FLAG_SCOPE_MASK   (static_cast<unsigned char>( \
-    TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
+#define TRACE_EVENT_FLAG_SCOPE_MASK                          \
+  (static_cast<unsigned int>(TRACE_EVENT_FLAG_SCOPE_OFFSET | \
+                             TRACE_EVENT_FLAG_SCOPE_EXTRA))
 
 // Type values for identifying types in the TraceValue union.
 #define TRACE_VALUE_TYPE_BOOL         (static_cast<unsigned char>(1))
@@ -1220,36 +1233,42 @@
    private:
     unsigned long long data_;
   };
-  TraceID(const void* id, unsigned char* flags)
-      : data_(static_cast<unsigned long long>(
-              reinterpret_cast<uintptr_t>(id))) {
+  TraceID(const void* id, unsigned int* flags)
+      : data_(
+            static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(id))) {
     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
   }
-  TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
+  TraceID(ForceMangle id, unsigned int* flags) : data_(id.data()) {
     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
   }
-  TraceID(DontMangle id, unsigned char* flags) : data_(id.data()) {
+  TraceID(DontMangle id, unsigned int* flags) : data_(id.data()) {}
+  TraceID(unsigned long long id, unsigned int* flags) : data_(id) {
+    (void)flags;
   }
-  TraceID(unsigned long long id, unsigned char* flags)
-      : data_(id) { (void)flags; }
-  TraceID(unsigned long id, unsigned char* flags)
-      : data_(id) { (void)flags; }
-  TraceID(unsigned int id, unsigned char* flags)
-      : data_(id) { (void)flags; }
-  TraceID(unsigned short id, unsigned char* flags)
-      : data_(id) { (void)flags; }
-  TraceID(unsigned char id, unsigned char* flags)
-      : data_(id) { (void)flags; }
-  TraceID(long long id, unsigned char* flags)
-      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(long id, unsigned char* flags)
-      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(int id, unsigned char* flags)
-      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(short id, unsigned char* flags)
-      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(signed char id, unsigned char* flags)
-      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(unsigned long id, unsigned int* flags) : data_(id) { (void)flags; }
+  TraceID(unsigned int id, unsigned int* flags) : data_(id) { (void)flags; }
+  TraceID(unsigned short id, unsigned int* flags) : data_(id) { (void)flags; }
+  TraceID(unsigned char id, unsigned int* flags) : data_(id) { (void)flags; }
+  TraceID(long long id, unsigned int* flags)
+      : data_(static_cast<unsigned long long>(id)) {
+    (void)flags;
+  }
+  TraceID(long id, unsigned int* flags)
+      : data_(static_cast<unsigned long long>(id)) {
+    (void)flags;
+  }
+  TraceID(int id, unsigned int* flags)
+      : data_(static_cast<unsigned long long>(id)) {
+    (void)flags;
+  }
+  TraceID(short id, unsigned int* flags)
+      : data_(static_cast<unsigned long long>(id)) {
+    (void)flags;
+  }
+  TraceID(signed char id, unsigned int* flags)
+      : data_(static_cast<unsigned long long>(id)) {
+    (void)flags;
+  }
 
   unsigned long long data() const { return data_; }
 
@@ -1380,7 +1399,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
         arg1_val) {
@@ -1391,7 +1410,7 @@
       num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
 }
 
-template<class ARG1_TYPE>
+template <class ARG1_TYPE>
 static inline base::trace_event::TraceEventHandle
 AddTraceEventWithThreadIdAndTimestamp(
     char phase,
@@ -1400,7 +1419,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val,
     const char* arg2_name,
@@ -1423,7 +1442,7 @@
       num_args, arg_names, arg_types, arg_values, convertable_values, flags);
 }
 
-template<class ARG2_TYPE>
+template <class ARG2_TYPE>
 static inline base::trace_event::TraceEventHandle
 AddTraceEventWithThreadIdAndTimestamp(
     char phase,
@@ -1432,7 +1451,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
     const char* arg2_name,
@@ -1463,7 +1482,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
     const char* arg2_name,
@@ -1489,7 +1508,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags) {
+    unsigned int flags) {
   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
       phase, category_group_enabled, name, id, thread_id, timestamp,
       kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
@@ -1500,14 +1519,14 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
-    unsigned char flags) {
+    unsigned int flags) {
   const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   const base::TraceTicks now = base::TraceTicks::Now();
   return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
                                                name, id, thread_id, now, flags);
 }
 
-template<class ARG1_TYPE>
+template <class ARG1_TYPE>
 static inline base::trace_event::TraceEventHandle
 AddTraceEventWithThreadIdAndTimestamp(
     char phase,
@@ -1516,7 +1535,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val) {
   const int num_args = 1;
@@ -1528,13 +1547,13 @@
       num_args, &arg1_name, arg_types, arg_values, NULL, flags);
 }
 
-template<class ARG1_TYPE>
+template <class ARG1_TYPE>
 static inline base::trace_event::TraceEventHandle AddTraceEvent(
     char phase,
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
@@ -1544,7 +1563,7 @@
                                                arg1_name, arg1_val);
 }
 
-template<class ARG1_TYPE, class ARG2_TYPE>
+template <class ARG1_TYPE, class ARG2_TYPE>
 static inline base::trace_event::TraceEventHandle
 AddTraceEventWithThreadIdAndTimestamp(
     char phase,
@@ -1553,7 +1572,7 @@
     unsigned long long id,
     int thread_id,
     const base::TraceTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val,
     const char* arg2_name,
@@ -1569,13 +1588,13 @@
       num_args, arg_names, arg_types, arg_values, NULL, flags);
 }
 
-template<class ARG1_TYPE, class ARG2_TYPE>
+template <class ARG1_TYPE, class ARG2_TYPE>
 static inline base::trace_event::TraceEventHandle AddTraceEvent(
     char phase,
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
-    unsigned char flags,
+    unsigned int flags,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val,
     const char* arg2_name,
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index 465649d..4d25014 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -12,6 +12,9 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/trace_event/trace_event.h"
 
+namespace base {
+namespace trace_event {
+
 namespace {
 
 int g_atrace_fd = -1;
@@ -24,28 +27,25 @@
     unsigned long long id,
     const char** arg_names,
     const unsigned char* arg_types,
-    const base::trace_event::TraceEvent::TraceValue* arg_values,
-    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>*
-        convertable_values,
-    unsigned char flags) {
-  std::string out = base::StringPrintf("%c|%d|%s", phase, getpid(), name);
+    const TraceEvent::TraceValue* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  std::string out = StringPrintf("%c|%d|%s", phase, getpid(), name);
   if (flags & TRACE_EVENT_FLAG_HAS_ID)
-    base::StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
+    StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
   out += '|';
 
-  for (int i = 0; i < base::trace_event::kTraceMaxNumArgs && arg_names[i];
-       ++i) {
+  for (int i = 0; i < kTraceMaxNumArgs && arg_names[i]; ++i) {
     if (i)
       out += ';';
     out += arg_names[i];
     out += '=';
     std::string::size_type value_start = out.length();
-    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE)
       convertable_values[i]->AppendAsTraceFormat(&out);
-    } else {
-      base::trace_event::TraceEvent::AppendValueAsJSON(arg_types[i],
-                                                       arg_values[i], &out);
-    }
+    else
+      TraceEvent::AppendValueAsJSON(arg_types[i], arg_values[i], &out);
+
     // Remove the quotes which may confuse the atrace script.
     ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
     ReplaceSubstringsAfterOffset(&out, value_start, "\"", "");
@@ -59,25 +59,21 @@
   write(g_atrace_fd, out.c_str(), out.size());
 }
 
-void NoOpOutputCallback(base::WaitableEvent* complete_event,
-                        const scoped_refptr<base::RefCountedString>&,
+void NoOpOutputCallback(WaitableEvent* complete_event,
+                        const scoped_refptr<RefCountedString>&,
                         bool has_more_events) {
   if (!has_more_events)
     complete_event->Signal();
 }
 
-void EndChromeTracing(base::trace_event::TraceLog* trace_log,
-                      base::WaitableEvent* complete_event) {
+void EndChromeTracing(TraceLog* trace_log, WaitableEvent* complete_event) {
   trace_log->SetDisabled();
   // Delete the buffered trace events as they have been sent to atrace.
-  trace_log->Flush(base::Bind(&NoOpOutputCallback, complete_event));
+  trace_log->Flush(Bind(&NoOpOutputCallback, complete_event));
 }
 
 }  // namespace
 
-namespace base {
-namespace trace_event {
-
 // These functions support Android systrace.py when 'webview' category is
 // traced. With the new adb_profile_chrome, we may have two phases:
 // - before WebView is ready for combined tracing, we can use adb_profile_chrome
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
index e83aa73..2da6258 100644
--- a/base/trace_event/trace_event_argument.cc
+++ b/base/trace_event/trace_event_argument.cc
@@ -5,112 +5,464 @@
 #include "base/trace_event/trace_event_argument.h"
 
 #include "base/json/json_writer.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
 #include "base/values.h"
 
 namespace base {
 namespace trace_event {
 
-TracedValue::TracedValue() : root_(new DictionaryValue()) {
-  stack_.push_back(root_.get());
+namespace {
+const char kTypeStartDict = '{';
+const char kTypeEndDict = '}';
+const char kTypeStartArray = '[';
+const char kTypeEndArray = ']';
+const char kTypeBool = 'b';
+const char kTypeInt = 'i';
+const char kTypeDouble = 'd';
+const char kTypeString = 's';
+const char kTypeCStr = '*';
+
+#ifndef NDEBUG
+const bool kStackTypeDict = false;
+const bool kStackTypeArray = true;
+#define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
+#define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
+#define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
+#else
+#define DCHECK_CURRENT_CONTAINER_IS(x) \
+  do {                                 \
+  } while (0)
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) \
+  do {                                     \
+  } while (0)
+#define DEBUG_PUSH_CONTAINER(x) \
+  do {                          \
+  } while (0)
+#define DEBUG_POP_CONTAINER() \
+  do {                        \
+  } while (0)
+#endif
+
+inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
+  pickle.WriteBytes(&kTypeCStr, 1);
+  pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
+}
+
+inline void WriteKeyNameAsStdString(Pickle& pickle, const std::string& str) {
+  pickle.WriteBytes(&kTypeString, 1);
+  pickle.WriteString(str);
+}
+
+std::string ReadKeyName(PickleIterator& pickle_iterator) {
+  const char* type = nullptr;
+  bool res = pickle_iterator.ReadBytes(&type, 1);
+  std::string key_name;
+  if (res && *type == kTypeCStr) {
+    uint64 ptr_value = 0;
+    res = pickle_iterator.ReadUInt64(&ptr_value);
+    key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
+  } else if (res && *type == kTypeString) {
+    res = pickle_iterator.ReadString(&key_name);
+  }
+  DCHECK(res);
+  return key_name;
+}
+}  // namespace
+
+TracedValue::TracedValue() : TracedValue(0) {}
+
+TracedValue::TracedValue(size_t capacity) {
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  if (capacity)
+    pickle_.Reserve(capacity);
 }
 
 TracedValue::~TracedValue() {
-  DCHECK_EQ(1u, stack_.size());
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
 }
 
 void TracedValue::SetInteger(const char* name, int value) {
-  GetCurrentDictionary()->SetInteger(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetIntegerWithCopiedName(const std::string& name, int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::SetDouble(const char* name, double value) {
-  GetCurrentDictionary()->SetDouble(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetDoubleWithCopiedName(const std::string& name,
+                                          double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::SetBoolean(const char* name, bool value) {
-  GetCurrentDictionary()->SetBoolean(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetBooleanWithCopiedName(const std::string& name,
+                                           bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::SetString(const char* name, const std::string& value) {
-  GetCurrentDictionary()->SetString(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
 }
 
-void TracedValue::SetValue(const char* name, scoped_ptr<Value> value) {
-  GetCurrentDictionary()->Set(name, value.Pass());
+void TracedValue::SetStringWithCopiedName(const std::string& name,
+                                          const std::string& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::SetValue(const char* name, const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionary(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
+}
+
+void TracedValue::SetValueWithCopiedName(const std::string& name,
+                                         const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionaryWithCopiedName(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
 }
 
 void TracedValue::BeginDictionary(const char* name) {
-  DictionaryValue* dictionary = new DictionaryValue();
-  GetCurrentDictionary()->Set(name, make_scoped_ptr(dictionary));
-  stack_.push_back(dictionary);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginDictionaryWithCopiedName(const std::string& name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::BeginArray(const char* name) {
-  ListValue* array = new ListValue();
-  GetCurrentDictionary()->Set(name, make_scoped_ptr(array));
-  stack_.push_back(array);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginArrayWithCopiedName(const std::string& name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::EndDictionary() {
-  DCHECK_GT(stack_.size(), 1u);
-  DCHECK(GetCurrentDictionary());
-  stack_.pop_back();
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndDict, 1);
 }
 
 void TracedValue::AppendInteger(int value) {
-  GetCurrentArray()->AppendInteger(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
 }
 
 void TracedValue::AppendDouble(double value) {
-  GetCurrentArray()->AppendDouble(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
 }
 
 void TracedValue::AppendBoolean(bool value) {
-  GetCurrentArray()->AppendBoolean(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
 }
 
 void TracedValue::AppendString(const std::string& value) {
-  GetCurrentArray()->AppendString(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
 }
 
 void TracedValue::BeginArray() {
-  ListValue* array = new ListValue();
-  GetCurrentArray()->Append(array);
-  stack_.push_back(array);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
 }
 
 void TracedValue::BeginDictionary() {
-  DictionaryValue* dictionary = new DictionaryValue();
-  GetCurrentArray()->Append(dictionary);
-  stack_.push_back(dictionary);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
 }
 
 void TracedValue::EndArray() {
-  DCHECK_GT(stack_.size(), 1u);
-  DCHECK(GetCurrentArray());
-  stack_.pop_back();
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndArray, 1);
 }
 
-DictionaryValue* TracedValue::GetCurrentDictionary() {
-  DCHECK(!stack_.empty());
-  DictionaryValue* dictionary = NULL;
-  stack_.back()->GetAsDictionary(&dictionary);
-  DCHECK(dictionary);
-  return dictionary;
+void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
+  SetBaseValueWithCopiedName(name, *value);
 }
 
-ListValue* TracedValue::GetCurrentArray() {
-  DCHECK(!stack_.empty());
-  ListValue* list = NULL;
-  stack_.back()->GetAsList(&list);
-  DCHECK(list);
-  return list;
+void TracedValue::SetBaseValueWithCopiedName(const std::string& name,
+                                             const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      SetBooleanWithCopiedName(name, bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      SetIntegerWithCopiedName(name, int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      SetDoubleWithCopiedName(name, double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      SetStringWithCopiedName(name, string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionaryWithCopiedName(name);
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArrayWithCopiedName(name);
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+void TracedValue::AppendBaseValue(const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      AppendBoolean(bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      AppendInteger(int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      AppendDouble(double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      AppendString(string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionary();
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArray();
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  DictionaryValue* cur_dict = root.get();
+  ListValue* cur_list = nullptr;
+  std::vector<Value*> stack;
+  PickleIterator it(pickle_);
+  const char* type;
+
+  while (it.ReadBytes(&type, 1)) {
+    DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
+    switch (*type) {
+      case kTypeStartDict: {
+        auto new_dict = new DictionaryValue();
+        if (cur_dict) {
+          cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_dict));
+          stack.push_back(cur_dict);
+          cur_dict = new_dict;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_dict));
+          stack.push_back(cur_list);
+          cur_list = nullptr;
+          cur_dict = new_dict;
+        }
+      } break;
+
+      case kTypeEndArray:
+      case kTypeEndDict: {
+        if (stack.back()->GetAsDictionary(&cur_dict)) {
+          cur_list = nullptr;
+        } else if (stack.back()->GetAsList(&cur_list)) {
+          cur_dict = nullptr;
+        }
+        stack.pop_back();
+      } break;
+
+      case kTypeStartArray: {
+        auto new_list = new ListValue();
+        if (cur_dict) {
+          cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_list));
+          stack.push_back(cur_dict);
+          cur_dict = nullptr;
+          cur_list = new_list;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_list));
+          stack.push_back(cur_list);
+          cur_list = new_list;
+        }
+      } break;
+
+      case kTypeBool: {
+        bool value;
+        CHECK(it.ReadBool(&value));
+        if (cur_dict) {
+          cur_dict->SetBoolean(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendBoolean(value);
+        }
+      } break;
+
+      case kTypeInt: {
+        int value;
+        CHECK(it.ReadInt(&value));
+        if (cur_dict) {
+          cur_dict->SetInteger(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendInteger(value);
+        }
+      } break;
+
+      case kTypeDouble: {
+        double value;
+        CHECK(it.ReadDouble(&value));
+        if (cur_dict) {
+          cur_dict->SetDouble(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendDouble(value);
+        }
+      } break;
+
+      case kTypeString: {
+        std::string value;
+        CHECK(it.ReadString(&value));
+        if (cur_dict) {
+          cur_dict->SetString(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendString(value);
+        }
+      } break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+  DCHECK(stack.empty());
+  return root.Pass();
 }
 
 void TracedValue::AppendAsTraceFormat(std::string* out) const {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
+
+  // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
+  // produce the JSON on its own. This will require refactoring JSONWriter
+  // to decouple the base::Value traversal from the JSON writing bits
   std::string tmp;
-  JSONWriter::Write(*stack_.front(), &tmp);
+  JSONWriter::Write(*ToBaseValue(), &tmp);
   *out += tmp;
-  DCHECK_EQ(1u, stack_.size()) << tmp;
+}
+
+void TracedValue::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("TracedValue",
+                pickle_.GetTotalAllocatedSize() /* allocated size */,
+                pickle_.size() /* resident size */);
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
index 56f7c61..aab58bc 100644
--- a/base/trace_event/trace_event_argument.h
+++ b/base/trace_event/trace_event_argument.h
@@ -9,11 +9,11 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
 #include "base/trace_event/trace_event.h"
 
 namespace base {
-class DictionaryValue;
-class ListValue;
+
 class Value;
 
 namespace trace_event {
@@ -21,18 +21,31 @@
 class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
  public:
   TracedValue();
+  explicit TracedValue(size_t capacity);
 
   void EndDictionary();
   void EndArray();
 
+  // These methods assume that |name| is a long lived "quoted" string.
   void SetInteger(const char* name, int value);
   void SetDouble(const char* name, double value);
   void SetBoolean(const char* name, bool value);
   void SetString(const char* name, const std::string& value);
-  void SetValue(const char* name, scoped_ptr<Value> value);
+  void SetValue(const char* name, const TracedValue& value);
   void BeginDictionary(const char* name);
   void BeginArray(const char* name);
 
+  // These, instead, can be safely passed a temporary string.
+  void SetIntegerWithCopiedName(const std::string& name, int value);
+  void SetDoubleWithCopiedName(const std::string& name, double value);
+  void SetBooleanWithCopiedName(const std::string& name, bool value);
+  void SetStringWithCopiedName(const std::string& name,
+                               const std::string& value);
+  void SetValueWithCopiedName(const std::string& name,
+                              const TracedValue& value);
+  void BeginDictionaryWithCopiedName(const std::string& name);
+  void BeginArrayWithCopiedName(const std::string& name);
+
   void AppendInteger(int);
   void AppendDouble(double);
   void AppendBoolean(bool);
@@ -40,16 +53,33 @@
   void BeginArray();
   void BeginDictionary();
 
+  // ConvertableToTraceFormat implementation.
   void AppendAsTraceFormat(std::string* out) const override;
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+  // DEPRECATED: do not use, here only for legacy reasons. These methods causes
+  // a copy-and-translation of the base::Value into the equivalent TracedValue.
+  // TODO(primiano): migrate the (three) existing clients to the cheaper
+  // SetValue(TracedValue) API. crbug.com/495628.
+  void SetValue(const char* name, scoped_ptr<base::Value> value);
+  void SetBaseValueWithCopiedName(const std::string& name,
+                                  const base::Value& value);
+  void AppendBaseValue(const base::Value& value);
+
+  // Public for tests only.
+  scoped_ptr<base::Value> ToBaseValue() const;
+
  private:
   ~TracedValue() override;
 
-  DictionaryValue* GetCurrentDictionary();
-  ListValue* GetCurrentArray();
+  Pickle pickle_;
 
-  scoped_ptr<base::Value> root_;
-  std::vector<Value*> stack_;  // Weak references.
+#ifndef NDEBUG
+  // In debug builds checks the pairings of {Start,End}{Dictionary,Array}
+  std::vector<bool> nesting_stack_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(TracedValue);
 };
 
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
index c59910e..cb1cf2e 100644
--- a/base/trace_event/trace_event_argument_unittest.cc
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -14,10 +15,11 @@
   value->SetDouble("double", 0.0);
   value->SetBoolean("bool", true);
   value->SetString("string", "string");
-  std::string json;
+  std::string json = "PREFIX";
   value->AppendAsTraceFormat(&json);
-  EXPECT_EQ("{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
-            json);
+  EXPECT_EQ(
+      "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
+      json);
 }
 
 TEST(TraceEventArgumentTest, Hierarchy) {
@@ -49,5 +51,96 @@
       json);
 }
 
+TEST(TraceEventArgumentTest, LongStrings) {
+  std::string kLongString = "supercalifragilisticexpialidocious";
+  std::string kLongString2 = "0123456789012345678901234567890123456789";
+  char kLongString3[4096];
+  for (size_t i = 0; i < sizeof(kLongString3); ++i)
+    kLongString3[i] = 'a' + (i % 25);
+  kLongString3[sizeof(kLongString3) - 1] = '\0';
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetString("a", "short");
+  value->SetString("b", kLongString);
+  value->BeginArray("c");
+  value->AppendString(kLongString2);
+  value->AppendString("");
+  value->BeginDictionary();
+  value->SetString("a", kLongString3);
+  value->EndDictionary();
+  value->EndArray();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" +
+                kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}",
+            json);
+}
+
+TEST(TraceEventArgumentTest, PassBaseValue) {
+  FundamentalValue int_value(42);
+  FundamentalValue bool_value(true);
+  FundamentalValue double_value(42.0f);
+
+  auto dict_value = make_scoped_ptr(new DictionaryValue);
+  dict_value->SetBoolean("bool", true);
+  dict_value->SetInteger("int", 42);
+  dict_value->SetDouble("double", 42.0f);
+  dict_value->SetString("string", std::string("a") + "b");
+  dict_value->SetString("string", std::string("a") + "b");
+
+  auto list_value = make_scoped_ptr(new ListValue);
+  list_value->AppendBoolean(false);
+  list_value->AppendInteger(1);
+  list_value->AppendString("in_list");
+  list_value->Append(dict_value.Pass());
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->BeginDictionary("outer_dict");
+  value->SetValue("inner_list", list_value.Pass());
+  value->EndDictionary();
+
+  dict_value.reset();
+  list_value.reset();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"outer_dict\":{\"inner_list\":[false,1,\"in_list\",{\"bool\":true,"
+      "\"double\":42.0,\"int\":42,\"string\":\"ab\"}]}}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, PassTracedValue) {
+  auto dict_value = make_scoped_refptr(new TracedValue);
+  dict_value->SetInteger("a", 1);
+
+  auto nested_dict_value = make_scoped_refptr(new TracedValue);
+  nested_dict_value->SetInteger("b", 2);
+  nested_dict_value->BeginArray("c");
+  nested_dict_value->AppendString("foo");
+  nested_dict_value->EndArray();
+
+  dict_value->SetValue("e", *nested_dict_value);
+
+  // Check the merged result.
+  std::string json;
+  dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json);
+
+  // Check that the passed nestd dict was left unouthced.
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json);
+
+  // And that it is still usable.
+  nested_dict_value->SetInteger("f", 3);
+  nested_dict_value->BeginDictionary("g");
+  nested_dict_value->EndDictionary();
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json);
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
index d199bf5..98e4553 100644
--- a/base/trace_event/trace_event_etw_export_win.cc
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/strings/string_tokenizer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_impl.h"
@@ -40,6 +41,55 @@
 tEventRegister EventRegisterProc = nullptr;
 tEventWrite EventWriteProc = nullptr;
 tEventUnregister EventUnregisterProc = nullptr;
+
+// |filtered_event_group_names| contains the event categories that can be
+// exported individually. These categories can be enabled by passing the correct
+// keyword when starting the trace. A keyword is a 64-bit flag and we attribute
+// one bit per category. We can therefore enable a particular category by
+// setting its corresponding bit in the keyword. For events that are not present
+// in |filtered_event_group_names|, we have two bits that control their
+// behaviour. When bit 61 is enabled, any event that is not disabled by default
+// (ie. doesn't start with disabled-by-default-) will be exported. Likewise,
+// when bit 62 is enabled, any event that is disabled by default will be
+// exported.
+//
+// Note that bit 63 (MSB) must always be set, otherwise tracing will be disabled
+// by ETW. Therefore, the keyword will always be greater than
+// 0x8000000000000000.
+//
+// Examples of passing keywords to the provider using xperf:
+// # This exports "benchmark" and "cc" events
+// xperf -start chrome -on Chrome:0x8000000000000009
+//
+// # This exports "gpu", "netlog" and all other events that are not disabled by
+// # default
+// xperf -start chrome -on Chrome:0xA0000000000000A0
+//
+// More info about starting a trace and keyword can be obtained by using the
+// help section of xperf (xperf -help start). Note that xperf documentation
+// refers to keywords as flags and there are two ways to enable them, using
+// group names or the hex representation. We only support the latter. Also, we
+// ignore the level.
+const char* const filtered_event_group_names[] = {
+    "benchmark",                                         // 0x1
+    "blink",                                             // 0x2
+    "browser",                                           // 0x4
+    "cc",                                                // 0x8
+    "evdev",                                             // 0x10
+    "gpu",                                               // 0x20
+    "input",                                             // 0x40
+    "netlog",                                            // 0x80
+    "renderer.scheduler",                                // 0x100
+    "toplevel",                                          // 0x200
+    "v8",                                                // 0x400
+    "disabled-by-default-cc.debug",                      // 0x800
+    "disabled-by-default-cc.debug.picture",              // 0x1000
+    "disabled-by-default-toplevel.flow"};                // 0x2000
+const char* other_events_group_name = "__OTHER_EVENTS";  // 0x2000000000000000
+const char* disabled_other_events_group_name =
+    "__DISABLED_OTHER_EVENTS";  // 0x4000000000000000
+uint64 other_events_keyword_bit = 1ULL << 61;
+uint64 disabled_other_events_keyword_bit = 1ULL << 62;
 }  // namespace
 
 // Redirector function for EventRegister. Called by macros in
@@ -77,7 +127,8 @@
 namespace base {
 namespace trace_event {
 
-TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
+TraceEventETWExport::TraceEventETWExport()
+    : etw_export_enabled_(false), etw_match_any_keyword_(0ULL) {
   // Find Advapi32.dll. This should always succeed.
   HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
   if (AdvapiDLL) {
@@ -92,6 +143,8 @@
     // Register the ETW provider. If registration fails then the event logging
     // calls will fail (on XP this call will do nothing).
     EventRegisterChrome();
+
+    UpdateEnabledCategories();
   }
 }
 
@@ -108,13 +161,18 @@
 // static
 void TraceEventETWExport::EnableETWExport() {
   if (GetInstance())
-    GetInstance()->ETWExportEnabled_ = true;
+    GetInstance()->etw_export_enabled_ = true;
 }
 
 // static
 void TraceEventETWExport::DisableETWExport() {
   if (GetInstance())
-    GetInstance()->ETWExportEnabled_ = false;
+    GetInstance()->etw_export_enabled_ = false;
+}
+
+// static
+bool TraceEventETWExport::IsETWExportEnabled() {
+  return (GetInstance() && GetInstance()->etw_export_enabled_);
 }
 
 // static
@@ -129,7 +187,7 @@
     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() || !GetInstance()->ETWExportEnabled_ ||
+  if (!GetInstance() || !GetInstance()->etw_export_enabled_ ||
       !EventEnabledChromeEvent())
     return;
 
@@ -211,7 +269,7 @@
       // *total* process CPU time when ETW tracing, and many of the strings
       // created exceed WPA's 4094 byte limit and are shown as:
       // "Unable to parse data". See crbug.com/488257
-      //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
+      // convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
     } else {
       TraceEvent::TraceValue trace_event;
       trace_event.as_uint = arg_values[i];
@@ -236,7 +294,7 @@
                                          const char* arg_value_2,
                                          const char* arg_name_3,
                                          const char* arg_value_3) {
-  if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+  if (!GetInstance() || !GetInstance()->etw_export_enabled_ ||
       !EventEnabledChromeEvent())
     return;
 
@@ -244,8 +302,78 @@
                         arg_value_2, arg_name_3, arg_value_3);
 }
 
-void TraceEventETWExport::Resurrect() {
-  StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
+// static
+bool TraceEventETWExport::IsCategoryGroupEnabled(
+    const char* category_group_name) {
+  DCHECK(category_group_name);
+  auto instance = GetInstance();
+  if (instance == nullptr)
+    return false;
+
+  if (!instance->IsETWExportEnabled())
+    return false;
+
+  CStringTokenizer category_group_tokens(
+      category_group_name, category_group_name + strlen(category_group_name),
+      ",");
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    if (instance->IsCategoryEnabled(category_group_token.c_str())) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool TraceEventETWExport::UpdateEnabledCategories() {
+  if (etw_match_any_keyword_ == CHROME_Context.MatchAnyKeyword)
+    return false;
+
+  // If the keyword has changed, update each category.
+  // Chrome_Context.MatchAnyKeyword is set by UIforETW (or other ETW trace
+  // recording tools) using the ETW infrastructure. This value will be set in
+  // all Chrome processes that have registered their ETW provider.
+  etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
+  for (int i = 0; i < ARRAYSIZE(filtered_event_group_names); i++) {
+    if (etw_match_any_keyword_ & (1ULL << i)) {
+      categories_status_[filtered_event_group_names[i]] = true;
+    } else {
+      categories_status_[filtered_event_group_names[i]] = false;
+    }
+  }
+
+  // Also update the two default categories.
+  if (etw_match_any_keyword_ & other_events_keyword_bit) {
+    categories_status_[other_events_group_name] = true;
+  } else {
+    categories_status_[other_events_group_name] = false;
+  }
+  if (etw_match_any_keyword_ & disabled_other_events_keyword_bit) {
+    categories_status_[disabled_other_events_group_name] = true;
+  } else {
+    categories_status_[disabled_other_events_group_name] = false;
+  }
+
+  return true;
+}
+
+bool TraceEventETWExport::IsCategoryEnabled(const char* category_name) const {
+  // Try to find the category and return its status if found
+  auto it = categories_status_.find(category_name);
+  if (it != categories_status_.end())
+    return it->second;
+
+  // Otherwise return the corresponding default status by first checking if the
+  // category is disabled by default.
+  if (StringPiece(category_name).starts_with("disabled-by-default")) {
+    DCHECK(categories_status_.find(disabled_other_events_group_name) !=
+           categories_status_.end());
+    return categories_status_.find(disabled_other_events_group_name)->second;
+  } else {
+    DCHECK(categories_status_.find(other_events_group_name) !=
+           categories_status_.end());
+    return categories_status_.find(other_events_group_name)->second;
+  }
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h
index eefe820..9f73d78 100644
--- a/base/trace_event/trace_event_etw_export_win.h
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -6,7 +6,10 @@
 #ifndef BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
 #define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
 
+#include <map>
+
 #include "base/base_export.h"
+#include "base/strings/string_piece.h"
 #include "base/trace_event/trace_event_impl.h"
 
 // Fwd.
@@ -29,9 +32,9 @@
   static void EnableETWExport();
   static void DisableETWExport();
 
-  static bool isETWExportEnabled() {
-    return (GetInstance() && GetInstance()->ETWExportEnabled_);
-  }
+  // Returns true if ETW is enabled. For now, this is true if the command line
+  // flag is specified.
+  static bool IsETWExportEnabled();
 
   // Exports an event to ETW. This is mainly used in
   // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
@@ -50,7 +53,7 @@
   // 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* phase,
                              const char* arg_name_1,
                              const char* arg_value_1,
                              const char* arg_name_2,
@@ -58,14 +61,30 @@
                              const char* arg_name_3,
                              const char* arg_value_3);
 
-  void Resurrect();
+  // Returns true if any category in the group is enabled.
+  static bool IsCategoryGroupEnabled(const char* category_group_name);
 
  private:
-  bool ETWExportEnabled_;
   // Ensure only the provider can construct us.
   friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
   TraceEventETWExport();
 
+  // Updates the list of enabled categories by consulting the ETW keyword.
+  // Returns true if there was a change, false otherwise.
+  bool UpdateEnabledCategories();
+
+  // Returns true if the category is enabled.
+  bool IsCategoryEnabled(const char* category_name) const;
+
+  // True if ETW is enabled. Allows hiding the exporting behind a flag.
+  bool etw_export_enabled_;
+
+  // Maps category names to their status (enabled/disabled).
+  std::map<base::StringPiece, bool> categories_status_;
+
+  // Local copy of the ETW keyword.
+  uint64 etw_match_any_keyword_;
+
   DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
 };
 
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 3d58d87..96858aa 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -33,6 +33,9 @@
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/time.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.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 
@@ -214,6 +217,18 @@
     return cloned_buffer.Pass();
   }
 
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    overhead->Add("TraceBufferRingBuffer", sizeof(*this));
+    for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+         queue_index = NextQueueIndex(queue_index)) {
+      size_t chunk_index = recyclable_chunks_queue_[queue_index];
+      if (chunk_index >= chunks_.size())  // Skip uninitialized chunks.
+        continue;
+      chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
  private:
   class ClonedTraceBuffer : public TraceBuffer {
    public:
@@ -242,6 +257,10 @@
       NOTIMPLEMENTED();
       return scoped_ptr<TraceBuffer>();
     }
+    void EstimateTraceMemoryOverhead(
+        TraceEventMemoryOverhead* overhead) override {
+      NOTIMPLEMENTED();
+    }
 
     size_t current_iteration_index_;
     ScopedVector<TraceBufferChunk> chunks_;
@@ -350,6 +369,23 @@
     return scoped_ptr<TraceBuffer>();
   }
 
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    const size_t chunks_ptr_vector_allocated_size =
+        sizeof(*this) + max_chunks_ * sizeof(decltype(chunks_)::value_type);
+    const size_t chunks_ptr_vector_resident_size =
+        sizeof(*this) + chunks_.size() * sizeof(decltype(chunks_)::value_type);
+    overhead->Add("TraceBufferVector", chunks_ptr_vector_allocated_size,
+                  chunks_ptr_vector_resident_size);
+    for (size_t i = 0; i < chunks_.size(); ++i) {
+      TraceBufferChunk* chunk = chunks_[i];
+      // Skip the in-flight (nullptr) chunks. They will be accounted by the
+      // per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
+      if (chunk)
+        chunk->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
  private:
   size_t in_flight_chunk_count_;
   size_t current_iteration_index_;
@@ -398,11 +434,16 @@
 
 }  // namespace
 
+TraceBufferChunk::TraceBufferChunk(uint32 seq) : next_free_(0), seq_(seq) {}
+
+TraceBufferChunk::~TraceBufferChunk() {}
+
 void TraceBufferChunk::Reset(uint32 new_seq) {
   for (size_t i = 0; i < next_free_; ++i)
     chunk_[i].Reset();
   next_free_ = 0;
   seq_ = new_seq;
+  cached_overhead_estimate_when_full_.reset();
 }
 
 TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
@@ -419,6 +460,31 @@
   return cloned_chunk.Pass();
 }
 
+void TraceBufferChunk::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (cached_overhead_estimate_when_full_) {
+    DCHECK(IsFull());
+    overhead->Update(*cached_overhead_estimate_when_full_);
+    return;
+  }
+
+  // Cache the memory overhead estimate only if the chunk is full.
+  TraceEventMemoryOverhead* estimate = overhead;
+  if (IsFull()) {
+    cached_overhead_estimate_when_full_.reset(new TraceEventMemoryOverhead);
+    estimate = cached_overhead_estimate_when_full_.get();
+  }
+
+  estimate->Add("TraceBufferChunk", sizeof(*this));
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].EstimateTraceMemoryOverhead(estimate);
+
+  if (IsFull()) {
+    estimate->AddSelf();
+    overhead->Update(*estimate);
+  }
+}
+
 // A helper class that allows the lock to be acquired in the middle of the scope
 // and unlocks at the end of scope if locked.
 class TraceLog::OptionalAutoLock {
@@ -529,7 +595,7 @@
     const unsigned char* arg_types,
     const unsigned long long* arg_values,
     const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
-    unsigned char flags) {
+    unsigned int flags) {
   timestamp_ = timestamp;
   thread_timestamp_ = thread_timestamp;
   duration_ = TimeDelta::FromInternalValue(-1);
@@ -610,6 +676,7 @@
   parameter_copy_storage_ = NULL;
   for (int i = 0; i < kTraceMaxNumArgs; ++i)
     convertable_values_[i] = NULL;
+  cached_memory_overhead_estimate_.reset();
 }
 
 void TraceEvent::UpdateDuration(const TraceTicks& now,
@@ -619,6 +686,29 @@
   thread_duration_ = thread_now - thread_timestamp_;
 }
 
+void TraceEvent::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (!cached_memory_overhead_estimate_) {
+    cached_memory_overhead_estimate_.reset(new TraceEventMemoryOverhead);
+    cached_memory_overhead_estimate_->Add("TraceEvent", sizeof(*this));
+    // TODO(primiano): parameter_copy_storage_ is refcounted and, in theory,
+    // could be shared by several events and we might overcount. In practice
+    // this is unlikely but it's worth checking.
+    if (parameter_copy_storage_) {
+      cached_memory_overhead_estimate_->AddRefCountedString(
+          *parameter_copy_storage_.get());
+    }
+    for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+        convertable_values_[i]->EstimateTraceMemoryOverhead(
+            cached_memory_overhead_estimate_.get());
+      }
+    }
+    cached_memory_overhead_estimate_->AddSelf();
+  }
+  overhead->Update(*cached_memory_overhead_estimate_);
+}
+
 // static
 void TraceEvent::AppendValueAsJSON(unsigned char type,
                                    TraceEvent::TraceValue value,
@@ -697,34 +787,34 @@
   DCHECK(!strchr(name_, '"'));
   StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
                      ","
-                     "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{",
+                     "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":",
                 process_id, thread_id_, time_int64, phase_, category_group_name,
                 name_);
 
   // Output argument names and values, stop at first NULL argument name.
-  if (arg_names_[0]) {
-    bool allow_args = argument_filter_predicate.is_null() ||
-                      argument_filter_predicate.Run(category_group_name, name_);
+  bool strip_args = arg_names_[0] && !argument_filter_predicate.is_null() &&
+                    !argument_filter_predicate.Run(category_group_name, name_);
 
-    if (allow_args) {
-      for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
-        if (i > 0)
-          *out += ",";
-        *out += "\"";
-        *out += arg_names_[i];
-        *out += "\":";
+  if (strip_args) {
+    *out += "\"__stripped__\"";
+  } else {
+    *out += "{";
 
-        if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-          convertable_values_[i]->AppendAsTraceFormat(out);
-        else
-          AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
-      }
-    } else {
-      *out += "\"stripped\":1";
+    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+      if (i > 0)
+        *out += ",";
+      *out += "\"";
+      *out += arg_names_[i];
+      *out += "\":";
+
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        convertable_values_[i]->AppendAsTraceFormat(out);
+      else
+        AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
     }
-  }
 
-  *out += "}";
+    *out += "}";
+  }
 
   if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
     int64 duration = duration_.ToInternalValue();
@@ -753,6 +843,9 @@
   if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
     StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64>(id_));
 
+  if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+    StringAppendF(out, ",\"bp\":\"e\"");
+
   // Instant events also output their scope.
   if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
     char scope = '?';
@@ -984,7 +1077,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 class TraceLog::ThreadLocalEventBuffer
-    : public MessageLoop::DestructionObserver {
+    : public MessageLoop::DestructionObserver,
+      public MemoryDumpProvider {
  public:
   ThreadLocalEventBuffer(TraceLog* trace_log);
   ~ThreadLocalEventBuffer() override;
@@ -1008,6 +1102,9 @@
   // MessageLoop::DestructionObserver
   void WillDestroyCurrentMessageLoop() override;
 
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
   void FlushWhileLocked();
 
   void CheckThisIsCurrentBuffer() const {
@@ -1036,6 +1133,10 @@
   MessageLoop* message_loop = MessageLoop::current();
   message_loop->AddDestructionObserver(this);
 
+  // This is to report the local memory usage when memory-infra is enabled.
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, ThreadTaskRunnerHandle::Get());
+
   AutoLock lock(trace_log->lock_);
   trace_log->thread_message_loops_.insert(message_loop);
 }
@@ -1043,6 +1144,7 @@
 TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
   CheckThisIsCurrentBuffer();
   MessageLoop::current()->RemoveDestructionObserver(this);
+  MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
 
   // Zero event_count_ happens in either of the following cases:
   // - no event generated for the thread;
@@ -1119,6 +1221,17 @@
   delete this;
 }
 
+bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(ProcessMemoryDump* pmd) {
+  if (!chunk_)
+    return true;
+  std::string dump_base_name = StringPrintf(
+      "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
+  TraceEventMemoryOverhead overhead;
+  chunk_->EstimateTraceMemoryOverhead(&overhead);
+  overhead.DumpInto(dump_base_name.c_str(), pmd);
+  return true;
+}
+
 void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
   if (!chunk_)
     return;
@@ -1195,11 +1308,46 @@
 #endif
 
   logged_events_.reset(CreateTraceBuffer());
+
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(this);
 }
 
 TraceLog::~TraceLog() {
 }
 
+void TraceLog::InitializeThreadLocalEventBufferIfSupported() {
+  // A ThreadLocalEventBuffer needs the message loop
+  // - to know when the thread exits;
+  // - to handle the final flush.
+  // For a thread without a message loop or the message loop may be blocked, the
+  // trace events will be added into the main buffer directly.
+  if (thread_blocks_message_loop_.Get() || !MessageLoop::current())
+    return;
+  auto thread_local_event_buffer = thread_local_event_buffer_.Get();
+  if (thread_local_event_buffer &&
+      !CheckGeneration(thread_local_event_buffer->generation())) {
+    delete thread_local_event_buffer;
+    thread_local_event_buffer = NULL;
+  }
+  if (!thread_local_event_buffer) {
+    thread_local_event_buffer = new ThreadLocalEventBuffer(this);
+    thread_local_event_buffer_.Set(thread_local_event_buffer);
+  }
+}
+
+bool TraceLog::OnMemoryDump(ProcessMemoryDump* pmd) {
+  TraceEventMemoryOverhead overhead;
+  overhead.Add("TraceLog", sizeof(*this));
+  {
+    AutoLock lock(lock_);
+    if (logged_events_)
+      logged_events_->EstimateTraceMemoryOverhead(&overhead);
+  }
+  overhead.AddSelf();
+  overhead.DumpInto("tracing/main_trace_log", pmd);
+  return true;
+}
+
 const unsigned char* TraceLog::GetCategoryGroupEnabled(
     const char* category_group) {
   TraceLog* tracelog = GetInstance();
@@ -1239,8 +1387,10 @@
       event_callback_trace_config_.IsCategoryGroupEnabled(category_group))
     enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
 #if defined(OS_WIN)
-  if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
+  if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
+          category_group)) {
     enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+  }
 #endif
 
   g_category_group_enabled[category_index] = enabled_flag;
@@ -1627,6 +1777,17 @@
 // 4. If any thread hasn't finish its flush in time, finish the flush.
 void TraceLog::Flush(const TraceLog::OutputCallback& cb,
                      bool use_worker_thread) {
+  FlushInternal(cb, use_worker_thread, false);
+}
+
+void TraceLog::CancelTracing(const OutputCallback& cb) {
+  SetDisabled();
+  FlushInternal(cb, false, true);
+}
+
+void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
+                             bool use_worker_thread,
+                             bool discard_events) {
   use_worker_thread_ = use_worker_thread;
   if (IsEnabled()) {
     // Can't flush when tracing is enabled because otherwise PostTask would
@@ -1670,17 +1831,17 @@
   if (thread_message_loop_task_runners.size()) {
     for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
       thread_message_loop_task_runners[i]->PostTask(
-          FROM_HERE,
-          Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
+          FROM_HERE, Bind(&TraceLog::FlushCurrentThread, Unretained(this),
+                          generation, discard_events));
     }
     flush_task_runner_->PostDelayedTask(
-        FROM_HERE,
-        Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
+        FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation,
+                        discard_events),
         TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
     return;
   }
 
-  FinishFlush(generation);
+  FinishFlush(generation, discard_events);
 }
 
 // Usually it runs on a different thread.
@@ -1693,28 +1854,24 @@
 
   // The callback need to be called at least once even if there is no events
   // to let the caller know the completion of flush.
-  bool has_more_events = true;
-  do {
-    scoped_refptr<RefCountedString> json_events_str_ptr =
-        new RefCountedString();
-
-    while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) {
-      const TraceBufferChunk* chunk = logged_events->NextChunk();
-      has_more_events = chunk != NULL;
-      if (!chunk)
-        break;
-      for (size_t j = 0; j < chunk->size(); ++j) {
-        if (json_events_str_ptr->size())
-          json_events_str_ptr->data().append(",\n");
-        chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
-                                           argument_filter_predicate);
+  scoped_refptr<RefCountedString> json_events_str_ptr = new RefCountedString();
+  while (const TraceBufferChunk* chunk = logged_events->NextChunk()) {
+    for (size_t j = 0; j < chunk->size(); ++j) {
+      size_t size = json_events_str_ptr->size();
+      if (size > kTraceEventBufferSizeInBytes) {
+        flush_output_callback.Run(json_events_str_ptr, true);
+        json_events_str_ptr = new RefCountedString();
+      } else if (size) {
+        json_events_str_ptr->data().append(",\n");
       }
+      chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
+                                         argument_filter_predicate);
     }
-    flush_output_callback.Run(json_events_str_ptr, has_more_events);
-  } while (has_more_events);
+  }
+  flush_output_callback.Run(json_events_str_ptr, false);
 }
 
-void TraceLog::FinishFlush(int generation) {
+void TraceLog::FinishFlush(int generation, bool discard_events) {
   scoped_ptr<TraceBuffer> previous_logged_events;
   OutputCallback flush_output_callback;
   TraceEvent::ArgumentFilterPredicate argument_filter_predicate;
@@ -1739,6 +1896,14 @@
     }
   }
 
+  if (discard_events) {
+    if (!flush_output_callback.is_null()) {
+      scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+      flush_output_callback.Run(empty_result, false);
+    }
+    return;
+  }
+
   if (use_worker_thread_ &&
       WorkerPool::PostTask(
           FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
@@ -1754,7 +1919,7 @@
 }
 
 // Run in each thread holding a local event buffer.
-void TraceLog::FlushCurrentThread(int generation) {
+void TraceLog::FlushCurrentThread(int generation, bool discard_events) {
   {
     AutoLock lock(lock_);
     if (!CheckGeneration(generation) || !flush_task_runner_) {
@@ -1772,10 +1937,11 @@
     return;
 
   flush_task_runner_->PostTask(
-      FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
+      FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation,
+                      discard_events));
 }
 
-void TraceLog::OnFlushTimeout(int generation) {
+void TraceLog::OnFlushTimeout(int generation, bool discard_events) {
   {
     AutoLock lock(lock_);
     if (!CheckGeneration(generation) || !flush_task_runner_) {
@@ -1794,7 +1960,7 @@
       LOG(WARNING) << "Thread: " << (*it)->thread_name();
     }
   }
-  FinishFlush(generation);
+  FinishFlush(generation, discard_events);
 }
 
 void TraceLog::FlushButLeaveBufferIntact(
@@ -1839,7 +2005,7 @@
     const unsigned char* arg_types,
     const unsigned long long* arg_values,
     const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
-    unsigned char flags) {
+    unsigned int flags) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   base::TraceTicks now = base::TraceTicks::Now();
   return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
@@ -1861,7 +2027,7 @@
     const unsigned char* arg_types,
     const unsigned long long* arg_values,
     const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
-    unsigned char flags) {
+    unsigned int flags) {
   TraceEventHandle handle = { 0, 0, 0 };
   if (!*category_group_enabled)
     return handle;
@@ -1885,24 +2051,10 @@
       OffsetNow() : offset_event_timestamp;
   ThreadTicks thread_now = ThreadNow();
 
-  ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
-  // A ThreadLocalEventBuffer needs the message loop
-  // - to know when the thread exits;
-  // - to handle the final flush.
-  // For a thread without a message loop or the message loop may be blocked, the
-  // trace events will be added into the main buffer directly.
-  if (!thread_blocks_message_loop_.Get() && MessageLoop::current()) {
-    thread_local_event_buffer = thread_local_event_buffer_.Get();
-    if (thread_local_event_buffer &&
-        !CheckGeneration(thread_local_event_buffer->generation())) {
-      delete thread_local_event_buffer;
-      thread_local_event_buffer = NULL;
-    }
-    if (!thread_local_event_buffer) {
-      thread_local_event_buffer = new ThreadLocalEventBuffer(this);
-      thread_local_event_buffer_.Set(thread_local_event_buffer);
-    }
-  }
+  // |thread_local_event_buffer_| can be null if the current thread doesn't have
+  // a message loop or the message loop is blocked.
+  InitializeThreadLocalEventBufferIfSupported();
+  auto thread_local_event_buffer = thread_local_event_buffer_.Get();
 
   // Check and update the current thread name only if the event is for the
   // current thread to avoid locks in most cases.
@@ -1927,8 +2079,9 @@
       } else {
         // This is a thread id that we've seen before, but potentially with a
         // new name.
-        std::vector<StringPiece> existing_names;
-        Tokenize(existing_name->second, ",", &existing_names);
+        std::vector<StringPiece> existing_names = base::SplitStringPiece(
+            existing_name->second, ",", base::KEEP_WHITESPACE,
+            base::SPLIT_WANT_NONEMPTY);
         bool found = std::find(existing_names.begin(),
                                existing_names.end(),
                                new_name) != existing_names.end();
@@ -2194,9 +2347,8 @@
       labels.push_back(it->second);
     }
     InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
-                            current_thread_id,
-                            "process_labels", "labels",
-                            JoinString(labels, ','));
+                            current_thread_id, "process_labels", "labels",
+                            base::JoinString(labels, ","));
   }
 
   // Thread sort indices.
@@ -2334,6 +2486,11 @@
   }
 }
 
+void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
+}
+
 }  // namespace trace_event
 }  // namespace base
 
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 7fdc5e3..a6e95f4 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -24,7 +24,9 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_local.h"
+#include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
 
 // Older style trace macros with explicit id and extra data
 // Only these macros result in publishing data to ETW as currently implemented.
@@ -65,6 +67,8 @@
   // appended.
   virtual void AppendAsTraceFormat(std::string* out) const = 0;
 
+  virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   std::string ToString() const {
     std::string result;
     AppendAsTraceFormat(&result);
@@ -117,12 +121,14 @@
       const unsigned char* arg_types,
       const unsigned long long* arg_values,
       const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
-      unsigned char flags);
+      unsigned int flags);
 
   void Reset();
 
   void UpdateDuration(const TraceTicks& now, const ThreadTicks& thread_now);
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead*);
+
   // Serialize event data to JSON
   typedef base::Callback<bool(const char* category_group_name,
                               const char* event_name)> ArgumentFilterPredicate;
@@ -142,7 +148,7 @@
   TimeDelta duration() const { return duration_; }
   TimeDelta thread_duration() const { return thread_duration_; }
   unsigned long long id() const { return id_; }
-  unsigned char flags() const { return flags_; }
+  unsigned int flags() const { return flags_; }
 
   // Exposed for unittesting:
 
@@ -168,6 +174,7 @@
   TimeDelta thread_duration_;
   // id_ can be used to store phase-specific data.
   unsigned long long id_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_memory_overhead_estimate_;
   TraceValue arg_values_[kTraceMaxNumArgs];
   const char* arg_names_[kTraceMaxNumArgs];
   scoped_refptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
@@ -176,7 +183,7 @@
   scoped_refptr<base::RefCountedString> parameter_copy_storage_;
   int thread_id_;
   char phase_;
-  unsigned char flags_;
+  unsigned int flags_;
   unsigned char arg_types_[kTraceMaxNumArgs];
 
   DISALLOW_COPY_AND_ASSIGN(TraceEvent);
@@ -185,10 +192,8 @@
 // TraceBufferChunk is the basic unit of TraceBuffer.
 class BASE_EXPORT TraceBufferChunk {
  public:
-  explicit TraceBufferChunk(uint32 seq)
-      : next_free_(0),
-        seq_(seq) {
-  }
+  explicit TraceBufferChunk(uint32 seq);
+  ~TraceBufferChunk();
 
   void Reset(uint32 new_seq);
   TraceEvent* AddTraceEvent(size_t* event_index);
@@ -209,10 +214,13 @@
 
   scoped_ptr<TraceBufferChunk> Clone() const;
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   static const size_t kTraceBufferChunkSize = 64;
 
  private:
   size_t next_free_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_when_full_;
   TraceEvent chunk_[kTraceBufferChunkSize];
   uint32 seq_;
 };
@@ -235,6 +243,11 @@
   virtual const TraceBufferChunk* NextChunk() = 0;
 
   virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
+
+  // Computes an estimate of the size of the buffer, including all the retained
+  // objects.
+  virtual void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) = 0;
 };
 
 // TraceResultBuffer collects and converts trace fragments returned by TraceLog
@@ -289,7 +302,7 @@
   size_t event_count;
 };
 
-class BASE_EXPORT TraceLog {
+class BASE_EXPORT TraceLog : public MemoryDumpProvider {
  public:
   enum Mode {
     DISABLED = 0,
@@ -321,6 +334,10 @@
   // Retrieves a copy (for thread-safety) of the current TraceConfig.
   TraceConfig GetCurrentTraceConfig() const;
 
+  // Initializes the thread-local event buffer, if not already initialized and
+  // if the current thread supports that (has a message loop).
+  void InitializeThreadLocalEventBufferIfSupported();
+
   // Enables normal tracing (recording trace events in the trace buffer).
   // See TraceConfig comments for details on how to control what categories
   // will be traced. If tracing has already been enabled, |category_filter| will
@@ -350,6 +367,8 @@
   // on-demand.
   class BASE_EXPORT EnabledStateObserver {
    public:
+    virtual ~EnabledStateObserver() = default;
+
     // Called just after the tracing system becomes enabled, outside of the
     // |lock_|. TraceLog::IsEnabled() is true at this point.
     virtual void OnTraceLogEnabled() = 0;
@@ -365,6 +384,10 @@
   TraceLogStatus GetStatus() const;
   bool BufferIsFull() const;
 
+  // Computes an estimate of the size of the TraceLog including all the retained
+  // objects.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   // Not using base::Callback because of its limited by 7 parameters.
   // Also, using primitive type allows directly passing callback from WebCore.
   // WARNING: It is possible for the previously set callback to be called
@@ -383,7 +406,7 @@
                                 const char* const arg_names[],
                                 const unsigned char arg_types[],
                                 const unsigned long long arg_values[],
-                                unsigned char flags);
+                                unsigned int flags);
 
   // Enable tracing for EventCallback.
   void SetEventCallbackEnabled(const TraceConfig& trace_config,
@@ -407,6 +430,9 @@
   void Flush(const OutputCallback& cb, bool use_worker_thread = false);
   void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
 
+  // Cancels tracing and discards collected data.
+  void CancelTracing(const OutputCallback& cb);
+
   // Called by TRACE_EVENT* macros, don't call this directly.
   // The name parameter is a category group for example:
   // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent")
@@ -427,7 +453,7 @@
       const unsigned char* arg_types,
       const unsigned long long* arg_values,
       const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
-      unsigned char flags);
+      unsigned int flags);
   TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
       char phase,
       const unsigned char* category_group_enabled,
@@ -440,7 +466,7 @@
       const unsigned char* arg_types,
       const unsigned long long* arg_values,
       const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
-      unsigned char flags);
+      unsigned int flags);
   static void AddTraceEventEtw(char phase,
                                const char* category_group,
                                const void* id,
@@ -528,6 +554,9 @@
   // by the Singleton class.
   friend struct DefaultSingletonTraits<TraceLog>;
 
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
   // Enable/disable each category group based on the current mode_,
   // category_filter_, event_callback_ and event_callback_category_filter_.
   // Enable the category group in the enabled mode if category_filter_ matches
@@ -547,7 +576,7 @@
   class OptionalAutoLock;
 
   TraceLog();
-  ~TraceLog();
+  ~TraceLog() override;
   const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
   void AddMetadataEventsWhileLocked();
 
@@ -572,16 +601,20 @@
   TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
                                        OptionalAutoLock* lock);
 
+  void FlushInternal(const OutputCallback& cb,
+                     bool use_worker_thread,
+                     bool discard_events);
+
   // |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 FlushCurrentThread(int generation, bool discard_events);
   // Usually it runs on a different thread.
   static void ConvertTraceEventsToTraceFormat(
       scoped_ptr<TraceBuffer> logged_events,
       const TraceLog::OutputCallback& flush_output_callback,
       const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate);
-  void FinishFlush(int generation);
-  void OnFlushTimeout(int generation);
+  void FinishFlush(int generation, bool discard_events);
+  void OnFlushTimeout(int generation, bool discard_events);
 
   int generation() const {
     return static_cast<int>(subtle::NoBarrier_Load(&generation_));
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
index 8959589..73c8536 100644
--- a/base/trace_event/trace_event_memory.cc
+++ b/base/trace_event/trace_event_memory.cc
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_local_storage.h"
 #include "base/trace_event/trace_event.h"
@@ -318,9 +319,9 @@
     input_string.assign(input);
   }
 
-  std::vector<std::string> lines;
-  size_t line_count = Tokenize(input_string, "\n", &lines);
-  if (line_count == 0) {
+  std::vector<std::string> lines = base::SplitString(
+      input_string, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  if (lines.empty()) {
     DLOG(WARNING) << "No lines found";
     return;
   }
@@ -330,10 +331,8 @@
   AppendHeapProfileTotalsAsTraceFormat(lines[0], output);
 
   // Handle the following stack trace lines.
-  for (size_t i = 1; i < line_count; ++i) {
-    const std::string& line = lines[i];
-    AppendHeapProfileLineAsTraceFormat(line, output);
-  }
+  for (size_t i = 1; i < lines.size(); i++)
+    AppendHeapProfileLineAsTraceFormat(lines[i], output);
   output->append("]\n");
 }
 
@@ -348,8 +347,8 @@
   //   55227 = Outstanding bytes (malloc bytes - free bytes)
   //   14653 = Total allocations (mallocs)
   // 2624014 = Total bytes (malloc bytes)
-  std::vector<std::string> tokens;
-  Tokenize(line, " :[]@", &tokens);
+  std::vector<std::string> tokens = base::SplitString(
+      line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
   if (tokens.size() < 4) {
     DLOG(WARNING) << "Invalid totals line " << line;
     return;
@@ -378,8 +377,8 @@
   // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to
   //                                 static strings from trace event categories
   //                                 and names.
-  std::vector<std::string> tokens;
-  Tokenize(line, " :[]@", &tokens);
+  std::vector<std::string> tokens = base::SplitString(
+      line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
   // It's valid to have no stack addresses, so only require 4 tokens.
   if (tokens.size() < 4) {
     DLOG(WARNING) << "Invalid line " << line;
diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h
index e2b3ae9..5b63db0 100644
--- a/base/trace_event/trace_event_memory.h
+++ b/base/trace_event/trace_event_memory.h
@@ -43,7 +43,7 @@
                         HeapProfilerStartFunction heap_profiler_start_function,
                         HeapProfilerStopFunction heap_profiler_stop_function,
                         GetHeapProfileFunction get_heap_profile_function);
-  virtual ~TraceMemoryController();
+  ~TraceMemoryController() override;
 
   // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
   void OnTraceLogEnabled() override;
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
new file mode 100644
index 0000000..9aea5c1
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.cc
@@ -0,0 +1,151 @@
+// 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_memory_overhead.h"
+
+#include <algorithm>
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/values.h"
+
+namespace {
+size_t RoundUp(size_t size, size_t alignment) {
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+TraceEventMemoryOverhead::TraceEventMemoryOverhead() {}
+
+TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {}
+
+void TraceEventMemoryOverhead::AddOrCreateInternal(
+    const char* object_type,
+    size_t count,
+    size_t allocated_size_in_bytes,
+    size_t resident_size_in_bytes) {
+  auto it = allocated_objects_.find(object_type);
+  if (it == allocated_objects_.end()) {
+    allocated_objects_.insert(std::make_pair(
+        object_type, ObjectCountAndSize({count, allocated_size_in_bytes,
+                                         resident_size_in_bytes})));
+    return;
+  }
+  it->second.count += count;
+  it->second.allocated_size_in_bytes += allocated_size_in_bytes;
+  it->second.resident_size_in_bytes += resident_size_in_bytes;
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t allocated_size_in_bytes) {
+  Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t allocated_size_in_bytes,
+                                   size_t resident_size_in_bytes) {
+  AddOrCreateInternal(object_type, 1, allocated_size_in_bytes,
+                      resident_size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::AddString(const std::string& str) {
+  // The number below are empirical and mainly based on profiling of real-world
+  // std::string implementations:
+  //  - even short string end up malloc()-inc at least 32 bytes.
+  //  - longer stings seem to malloc() multiples of 16 bytes.
+  Add("std::string",
+      sizeof(std::string) + std::max<size_t>(RoundUp(str.capacity(), 16), 32u));
+}
+
+void TraceEventMemoryOverhead::AddRefCountedString(
+    const RefCountedString& str) {
+  Add("RefCountedString", sizeof(RefCountedString));
+  AddString(str.data());
+}
+
+void TraceEventMemoryOverhead::AddValue(const Value& value) {
+  switch (value.GetType()) {
+    case Value::TYPE_NULL:
+    case Value::TYPE_BOOLEAN:
+    case Value::TYPE_INTEGER:
+    case Value::TYPE_DOUBLE:
+      Add("FundamentalValue", sizeof(Value));
+      break;
+
+    case Value::TYPE_STRING: {
+      const StringValue* string_value = nullptr;
+      value.GetAsString(&string_value);
+      Add("StringValue", sizeof(StringValue));
+      AddString(string_value->GetString());
+    } break;
+
+    case Value::TYPE_BINARY: {
+      const BinaryValue* binary_value = nullptr;
+      value.GetAsBinary(&binary_value);
+      Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
+    } break;
+
+    case Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dictionary_value = nullptr;
+      value.GetAsDictionary(&dictionary_value);
+      Add("DictionaryValue", sizeof(DictionaryValue));
+      for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
+           it.Advance()) {
+        AddString(it.key());
+        AddValue(it.value());
+      }
+    } break;
+
+    case Value::TYPE_LIST: {
+      const ListValue* list_value = nullptr;
+      value.GetAsList(&list_value);
+      Add("ListValue", sizeof(ListValue));
+      for (const Value* v : *list_value)
+        AddValue(*v);
+    } break;
+
+    default:
+      NOTREACHED();
+  }
+}
+
+void TraceEventMemoryOverhead::AddSelf() {
+  size_t estimated_size = sizeof(*this);
+  // If the SmallMap did overflow its static capacity, its elements will be
+  // allocated on the heap and have to be accounted separately.
+  if (allocated_objects_.UsingFullMap())
+    estimated_size += sizeof(map_type::value_type) * allocated_objects_.size();
+  Add("TraceEventMemoryOverhead", estimated_size);
+}
+
+void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
+  for (const auto& it : other.allocated_objects_) {
+    AddOrCreateInternal(it.first, it.second.count,
+                        it.second.allocated_size_in_bytes,
+                        it.second.resident_size_in_bytes);
+  }
+}
+
+void TraceEventMemoryOverhead::DumpInto(const char* base_name,
+                                        ProcessMemoryDump* pmd) const {
+  for (const auto& it : allocated_objects_) {
+    std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
+    MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
+    mad->AddScalar(MemoryAllocatorDump::kNameSize,
+                   MemoryAllocatorDump::kUnitsBytes,
+                   it.second.allocated_size_in_bytes);
+    mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
+                   it.second.resident_size_in_bytes);
+    mad->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                   MemoryAllocatorDump::kUnitsObjects, it.second.count);
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h
new file mode 100644
index 0000000..8ecf12d
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.h
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+
+namespace base {
+
+class RefCountedString;
+class Value;
+
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// Used to estimate the memory overhead of the tracing infrastructure.
+class BASE_EXPORT TraceEventMemoryOverhead {
+ public:
+  TraceEventMemoryOverhead();
+  ~TraceEventMemoryOverhead();
+
+  // Use this method to account the overhead of an object for which an estimate
+  // is known for both the allocated and resident memory.
+  void Add(const char* object_type,
+           size_t allocated_size_in_bytes,
+           size_t resident_size_in_bytes);
+
+  // Similar to Add() above, but assumes that
+  // |resident_size_in_bytes| == |allocated_size_in_bytes|.
+  void Add(const char* object_type, size_t allocated_size_in_bytes);
+
+  // Specialized profiling functions for commonly used object types.
+  void AddString(const std::string& str);
+  void AddValue(const Value& value);
+  void AddRefCountedString(const RefCountedString& str);
+
+  // Call this after all the Add* methods above to account the memory used by
+  // this TraceEventMemoryOverhead instance itself.
+  void AddSelf();
+
+  // Adds up and merges all the values from |other| to this instance.
+  void Update(const TraceEventMemoryOverhead& other);
+
+  void DumpInto(const char* base_name, ProcessMemoryDump* pmd) const;
+
+ private:
+  struct ObjectCountAndSize {
+    size_t count;
+    size_t allocated_size_in_bytes;
+    size_t resident_size_in_bytes;
+  };
+  using map_type = SmallMap<hash_map<const char*, ObjectCountAndSize>, 16>;
+  map_type allocated_objects_;
+
+  void AddOrCreateInternal(const char* object_type,
+                           size_t count,
+                           size_t allocated_size_in_bytes,
+                           size_t resident_size_in_bytes);
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventMemoryOverhead);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
diff --git a/base/trace_event/trace_event_system_stats_monitor.h b/base/trace_event/trace_event_system_stats_monitor.h
index 051669a..7a63a14 100644
--- a/base/trace_event/trace_event_system_stats_monitor.h
+++ b/base/trace_event/trace_event_system_stats_monitor.h
@@ -33,7 +33,7 @@
   explicit TraceEventSystemStatsMonitor(
       scoped_refptr<SingleThreadTaskRunner> task_runner);
 
-  virtual ~TraceEventSystemStatsMonitor();
+  ~TraceEventSystemStatsMonitor() override;
 
   // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
   void OnTraceLogEnabled() override;
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 2449d54..8248f28 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/memory/singleton.h"
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/pattern.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
@@ -47,6 +48,8 @@
 const char kAsyncIdStr[] = "0x5";
 const int kAsyncId2 = 6;
 const char kAsyncId2Str[] = "0x6";
+const int kFlowId = 7;
+const char kFlowIdStr[] = "0x7";
 
 const  char kRecordAllCategoryFilter[] = "*";
 
@@ -85,7 +88,14 @@
                                         TraceLog::RECORDING_MODE);
   }
 
+  void CancelTrace() {
+    WaitableEvent flush_complete_event(false, false);
+    CancelTraceAsync(&flush_complete_event);
+    flush_complete_event.Wait();
+  }
+
   void EndTraceAndFlush() {
+    num_flush_callbacks_ = 0;
     WaitableEvent flush_complete_event(false, false);
     EndTraceAndFlushAsync(&flush_complete_event);
     flush_complete_event.Wait();
@@ -103,6 +113,13 @@
     flush_complete_event.Wait();
   }
 
+  void CancelTraceAsync(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->CancelTracing(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
   void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
     TraceLog::GetInstance()->SetDisabled();
     TraceLog::GetInstance()->Flush(
@@ -134,6 +151,7 @@
     ASSERT_FALSE(tracelog->IsEnabled());
     trace_buffer_.SetOutputCallback(json_output_.GetCallback());
     event_watch_notification_ = 0;
+    num_flush_callbacks_ = 0;
   }
   void TearDown() override {
     if (TraceLog::GetInstance())
@@ -150,6 +168,7 @@
   TraceResultBuffer trace_buffer_;
   TraceResultBuffer::SimpleOutput json_output_;
   int event_watch_notification_;
+  size_t num_flush_callbacks_;
 
  private:
   // We want our singleton torn down after each test.
@@ -161,6 +180,10 @@
     WaitableEvent* flush_complete_event,
     const scoped_refptr<base::RefCountedString>& events_str,
     bool has_more_events) {
+  num_flush_callbacks_++;
+  if (num_flush_callbacks_ > 1) {
+    EXPECT_FALSE(events_str->data().empty());
+  }
   AutoLock lock(lock_);
   json_output_.json_output.clear();
   trace_buffer_.Start();
@@ -430,6 +453,12 @@
                            "name1", "value1",
                            "name2", "value2");
 
+    TRACE_EVENT_FLOW_BEGIN0("all", "TRACE_EVENT_FLOW_BEGIN0 call", kFlowId);
+    TRACE_EVENT_FLOW_STEP0("all", "TRACE_EVENT_FLOW_STEP0 call", kFlowId,
+                           "step1");
+    TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(
+        "all", "TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
+
     TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", kAsyncId, NULL);
     TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", kAsyncId, "value");
     TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", kAsyncId, NULL);
@@ -613,6 +642,17 @@
   EXPECT_SUB_FIND_("name2");
   EXPECT_SUB_FIND_("value2");
 
+  EXPECT_FIND_("TRACE_EVENT_FLOW_BEGIN0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+  EXPECT_FIND_("TRACE_EVENT_FLOW_STEP0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+  EXPECT_SUB_FIND_("step1");
+  EXPECT_FIND_("TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+
   EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
   EXPECT_SUB_FIND_("id");
   EXPECT_SUB_FIND_(kAsyncIdStr);
@@ -882,6 +922,19 @@
   ValidateAllTraceMacrosCreatedData(trace_parsed_);
 }
 
+// Emit some events and validate that only empty strings are received
+// if we tell Flush() to discard events.
+TEST_F(TraceEventTestFixture, DataDiscarded) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  TraceWithAllMacroVariants(NULL);
+
+  CancelTrace();
+
+  EXPECT_TRUE(trace_parsed_.empty());
+}
+
 class MockEnabledStateChangedObserver :
       public TraceLog::EnabledStateObserver {
  public:
@@ -968,7 +1021,7 @@
     : public TraceLog::EnabledStateObserver {
  public:
   AfterStateChangeEnabledStateObserver() {}
-  virtual ~AfterStateChangeEnabledStateObserver() {}
+  ~AfterStateChangeEnabledStateObserver() override {}
 
   // TraceLog::EnabledStateObserver overrides:
   void OnTraceLogEnabled() override {
@@ -999,7 +1052,7 @@
     : public TraceLog::EnabledStateObserver {
  public:
   SelfRemovingEnabledStateObserver() {}
-  virtual ~SelfRemovingEnabledStateObserver() {}
+  ~SelfRemovingEnabledStateObserver() override {}
 
   // TraceLog::EnabledStateObserver overrides:
   void OnTraceLogEnabled() override {}
@@ -1052,6 +1105,43 @@
   EndTraceAndFlush();
 }
 
+TEST_F(TraceEventTestFixture, TestTraceFlush) {
+  size_t min_traces = 1;
+  size_t max_traces = 1;
+  do {
+    max_traces *= 2;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < max_traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+  } while (num_flush_callbacks_ < 2);
+
+  while (min_traces + 50 < max_traces) {
+    size_t traces = (min_traces + max_traces) / 2;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+    if (num_flush_callbacks_ < 2) {
+      min_traces = traces - 10;
+    } else {
+      max_traces = traces + 10;
+    }
+  }
+
+  for (size_t traces = min_traces; traces < max_traces; traces++) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+  }
+}
 
 // Test that categories work.
 TEST_F(TraceEventTestFixture, Categories) {
@@ -2149,8 +2239,8 @@
 
 bool IsTraceEventArgsWhitelisted(const char* category_group_name,
                                  const char* event_name) {
-  if (MatchPattern(category_group_name, "toplevel") &&
-      MatchPattern(event_name, "*")) {
+  if (base::MatchPattern(category_group_name, "toplevel") &&
+      base::MatchPattern(event_name, "*")) {
     return true;
   }
 
@@ -2187,7 +2277,10 @@
   dict->GetDictionary("args", &args_dict);
   ASSERT_TRUE(args_dict);
   EXPECT_FALSE(args_dict->GetInteger("int_two", &int_value));
-  EXPECT_TRUE(args_dict->GetInteger("stripped", &int_value));
+
+  std::string args_string;
+  EXPECT_TRUE(dict->GetString("args", &args_string));
+  EXPECT_EQ(args_string, "__stripped__");
 }
 
 class TraceEventCallbackTest : public TraceEventTestFixture {
@@ -2247,7 +2340,7 @@
                        const char* const arg_names[],
                        const unsigned char arg_types[],
                        const unsigned long long arg_values[],
-                       unsigned char flags) {
+                       unsigned int flags) {
     s_instance->collected_events_phases_.push_back(phase);
     s_instance->collected_events_categories_.push_back(
         TraceLog::GetCategoryGroupName(category_group_enabled));
diff --git a/base/trace_event/trace_event_win.cc b/base/trace_event/trace_event_win.cc
index ebb55c8..fdbd35a 100644
--- a/base/trace_event/trace_event_win.cc
+++ b/base/trace_event/trace_event_win.cc
@@ -16,16 +16,24 @@
 
 // {3DADA31D-19EF-4dc1-B345-037927193422}
 const GUID kChromeTraceProviderName = {
-    0x3dada31d, 0x19ef, 0x4dc1, 0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22 };
+    0x3dada31d,
+    0x19ef,
+    0x4dc1,
+    {0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22}};
 
 // {B967AE67-BB22-49d7-9406-55D91EE1D560}
 const GUID kTraceEventClass32 = {
-    0xb967ae67, 0xbb22, 0x49d7, 0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60 };
+    0xb967ae67,
+    0xbb22,
+    0x49d7,
+    {0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60}};
 
 // {97BE602D-2930-4ac3-8046-B6763B631DFE}
 const GUID kTraceEventClass64 = {
-    0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe};
-
+    0x97be602d,
+    0x2930,
+    0x4ac3,
+    {0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe}};
 
 TraceEventETWProvider::TraceEventETWProvider() :
     EtwTraceProvider(kChromeTraceProviderName) {
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
index 82bb016..d56d8d3 100644
--- a/base/trace_event/winheap_dump_provider_win.cc
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -6,6 +6,7 @@
 
 #include <windows.h>
 
+#include "base/debug/profiler.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/win/windows_version.h"
 
@@ -59,6 +60,13 @@
   if (base::win::GetVersion() < base::win::VERSION_VISTA)
     return false;
 
+// Disable this dump provider for the SyzyASan instrumented build
+// because they don't support the heap walking functions yet.
+#if defined(SYZYASAN)
+  if (base::debug::IsBinaryInstrumented())
+    return false;
+#endif
+
   // Retrieves the number of heaps in the current process.
   DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
   WinHeapInfo all_heap_info = {0};
diff --git a/base/values.cc b/base/values.cc
index 4534d27..5374d6c 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -482,27 +482,29 @@
   SetWithoutPathExpansion(path, new StringValue(in_value));
 }
 
-bool DictionaryValue::Get(const std::string& path,
-                          const Value** out_value) const {
+bool DictionaryValue::Get(StringPiece path, const Value** out_value) const {
   DCHECK(IsStringUTF8(path));
-  std::string current_path(path);
+  StringPiece current_path(path);
   const DictionaryValue* current_dictionary = this;
   for (size_t delimiter_position = current_path.find('.');
        delimiter_position != std::string::npos;
        delimiter_position = current_path.find('.')) {
     const DictionaryValue* child_dictionary = NULL;
-    if (!current_dictionary->GetDictionary(
-            current_path.substr(0, delimiter_position), &child_dictionary))
+    if (!current_dictionary->GetDictionaryWithoutPathExpansion(
+            current_path.substr(0, delimiter_position).as_string(),
+            &child_dictionary)) {
       return false;
+    }
 
     current_dictionary = child_dictionary;
-    current_path.erase(0, delimiter_position + 1);
+    current_path = current_path.substr(delimiter_position + 1);
   }
 
-  return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+  return current_dictionary->GetWithoutPathExpansion(current_path.as_string(),
+                                                     out_value);
 }
 
-bool DictionaryValue::Get(const std::string& path, Value** out_value)  {
+bool DictionaryValue::Get(StringPiece path, Value** out_value) {
   return static_cast<const DictionaryValue&>(*this).Get(
       path,
       const_cast<const Value**>(out_value));
@@ -588,7 +590,7 @@
       const_cast<const BinaryValue**>(out_value));
 }
 
-bool DictionaryValue::GetDictionary(const std::string& path,
+bool DictionaryValue::GetDictionary(StringPiece path,
                                     const DictionaryValue** out_value) const {
   const Value* value;
   bool result = Get(path, &value);
@@ -601,7 +603,7 @@
   return true;
 }
 
-bool DictionaryValue::GetDictionary(const std::string& path,
+bool DictionaryValue::GetDictionary(StringPiece path,
                                     DictionaryValue** out_value) {
   return static_cast<const DictionaryValue&>(*this).GetDictionary(
       path,
diff --git a/base/values.h b/base/values.h
index 7feef9d..0ff6217 100644
--- a/base/values.h
+++ b/base/values.h
@@ -30,6 +30,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
 
 namespace base {
 
@@ -270,8 +271,8 @@
   // Otherwise, it will return false and |out_value| will be untouched.
   // Note that the dictionary always owns the value that's returned.
   // |out_value| is optional and will only be set if non-NULL.
-  bool Get(const std::string& path, const Value** out_value) const;
-  bool Get(const std::string& path, Value** out_value);
+  bool Get(StringPiece path, const Value** out_value) const;
+  bool Get(StringPiece path, Value** out_value);
 
   // These are convenience forms of Get().  The value will be retrieved
   // and the return value will be true if the path is valid and the value at
@@ -287,9 +288,8 @@
   bool GetStringASCII(const std::string& path, std::string* out_value) const;
   bool GetBinary(const std::string& path, const BinaryValue** out_value) const;
   bool GetBinary(const std::string& path, BinaryValue** out_value);
-  bool GetDictionary(const std::string& path,
-                     const DictionaryValue** out_value) const;
-  bool GetDictionary(const std::string& path, DictionaryValue** out_value);
+  bool GetDictionary(StringPiece path, const DictionaryValue** out_value) const;
+  bool GetDictionary(StringPiece path, DictionaryValue** out_value);
   bool GetList(const std::string& path, const ListValue** out_value) const;
   bool GetList(const std::string& path, ListValue** out_value);
 
diff --git a/base/version.cc b/base/version.cc
index ede8a45..228dcb8 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -24,15 +24,17 @@
 // parsed successfully, false otherwise.
 bool ParseVersionNumbers(const std::string& version_str,
                          std::vector<uint32_t>* parsed) {
-  std::vector<std::string> numbers;
-  SplitString(version_str, '.', &numbers);
+  std::vector<StringPiece> numbers =
+      SplitStringPiece(version_str, ".", KEEP_WHITESPACE, SPLIT_WANT_ALL);
   if (numbers.empty())
     return false;
 
-  for (std::vector<std::string>::const_iterator it = numbers.begin();
-       it != numbers.end(); ++it) {
-    if (StartsWithASCII(*it, "+", false))
+  for (auto it = numbers.begin(); it != numbers.end(); ++it) {
+    if (StartsWith(*it, "+", CompareCase::SENSITIVE))
       return false;
+
+    // TODO(brettw) when we have a StringPiece version of StringToUint, delete
+    // this string conversion.
     unsigned int num;
     if (!StringToUint(*it, &num))
       return false;
@@ -98,8 +100,8 @@
 // static
 bool Version::IsValidWildcardString(const std::string& wildcard_string) {
   std::string version_string = wildcard_string;
-  if (EndsWith(wildcard_string.c_str(), ".*", false))
-    version_string = wildcard_string.substr(0, wildcard_string.size() - 2);
+  if (EndsWith(version_string, ".*", CompareCase::SENSITIVE))
+    version_string.resize(version_string.size() - 2);
 
   Version version(version_string);
   return version.IsValid();
@@ -117,7 +119,7 @@
   DCHECK(Version::IsValidWildcardString(wildcard_string));
 
   // Default behavior if the string doesn't end with a wildcard.
-  if (!EndsWith(wildcard_string.c_str(), ".*", false)) {
+  if (!EndsWith(wildcard_string, ".*", CompareCase::SENSITIVE)) {
     Version version(wildcard_string);
     DCHECK(version.IsValid());
     return CompareTo(version);
diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc
index 13acd65..2e6ed40 100644
--- a/base/win/iat_patch_function.cc
+++ b/base/win/iat_patch_function.cc
@@ -219,10 +219,9 @@
 
 IATPatchFunction::IATPatchFunction()
     : module_handle_(NULL),
+      intercept_function_(NULL),
       original_function_(NULL),
-      iat_thunk_(NULL),
-      intercept_function_(NULL) {
-}
+      iat_thunk_(NULL) {}
 
 IATPatchFunction::~IATPatchFunction() {
   if (NULL != intercept_function_) {
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
index 373c0c3..ade12fe 100644
--- a/base/win/scoped_comptr.h
+++ b/base/win/scoped_comptr.h
@@ -52,24 +52,24 @@
   // Note that this function equates to IUnknown::Release and should not
   // be confused with e.g. scoped_ptr::release().
   void Release() {
-    if (ptr_ != NULL) {
-      ptr_->Release();
-      ptr_ = NULL;
+    if (this->ptr_ != NULL) {
+      this->ptr_->Release();
+      this->ptr_ = NULL;
     }
   }
 
   // Sets the internal pointer to NULL and returns the held object without
   // releasing the reference.
   Interface* Detach() {
-    Interface* p = ptr_;
-    ptr_ = NULL;
+    Interface* p = this->ptr_;
+    this->ptr_ = NULL;
     return p;
   }
 
   // Accepts an interface pointer that has already been addref-ed.
   void Attach(Interface* p) {
-    DCHECK(!ptr_);
-    ptr_ = p;
+    DCHECK(!this->ptr_);
+    this->ptr_ = p;
   }
 
   // Retrieves the pointer address.
@@ -77,8 +77,8 @@
   // The function DCHECKs on the current value being NULL.
   // Usage: Foo(p.Receive());
   Interface** Receive() {
-    DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
-    return &ptr_;
+    DCHECK(!this->ptr_) << "Object leak. Pointer must be NULL";
+    return &this->ptr_;
   }
 
   // A convenience for whenever a void pointer is needed as an out argument.
@@ -89,18 +89,18 @@
   template <class Query>
   HRESULT QueryInterface(Query** p) {
     DCHECK(p != NULL);
-    DCHECK(ptr_ != NULL);
+    DCHECK(this->ptr_ != NULL);
     // IUnknown already has a template version of QueryInterface
     // so the iid parameter is implicit here. The only thing this
     // function adds are the DCHECKs.
-    return ptr_->QueryInterface(p);
+    return this->ptr_->QueryInterface(p);
   }
 
   // QI for times when the IID is not associated with the type.
   HRESULT QueryInterface(const IID& iid, void** obj) {
     DCHECK(obj != NULL);
-    DCHECK(ptr_ != NULL);
-    return ptr_->QueryInterface(iid, obj);
+    DCHECK(this->ptr_ != NULL);
+    return this->ptr_->QueryInterface(iid, obj);
   }
 
   // Queries |other| for the interface this object wraps and returns the
@@ -113,18 +113,18 @@
   // Convenience wrapper around CoCreateInstance
   HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
                          DWORD context = CLSCTX_ALL) {
-    DCHECK(!ptr_);
+    DCHECK(!this->ptr_);
     HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
-                                    reinterpret_cast<void**>(&ptr_));
+                                    reinterpret_cast<void**>(&this->ptr_));
     return hr;
   }
 
   // Checks if the identity of |other| and this object is the same.
   bool IsSameObject(IUnknown* other) {
-    if (!other && !ptr_)
+    if (!other && !this->ptr_)
       return true;
 
-    if (!other || !ptr_)
+    if (!other || !this->ptr_)
       return false;
 
     ScopedComPtr<IUnknown> my_identity;
@@ -147,8 +147,8 @@
   // by statically casting the ScopedComPtr instance to the wrapped interface
   // and then making the call... but generally that shouldn't be necessary.
   BlockIUnknownMethods* operator->() const {
-    DCHECK(ptr_ != NULL);
-    return reinterpret_cast<BlockIUnknownMethods*>(ptr_);
+    DCHECK(this->ptr_ != NULL);
+    return reinterpret_cast<BlockIUnknownMethods*>(this->ptr_);
   }
 
   // Pull in operator=() from the parent class.
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
index d38752d..23090b0 100644
--- a/base/win/scoped_comptr_unittest.cc
+++ b/base/win/scoped_comptr_unittest.cc
@@ -25,8 +25,10 @@
 };
 
 extern const IID dummy_iid;
-const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
-                        01, 23, 45 };
+const IID dummy_iid = {0x12345678u,
+                       0x1234u,
+                       0x5678u,
+                       {01, 23, 45, 67, 89, 01, 23, 45}};
 
 }  // namespace
 
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
index f57ab93..2cf2657 100644
--- a/base/win/scoped_variant.cc
+++ b/base/win/scoped_variant.cc
@@ -9,7 +9,7 @@
 namespace win {
 
 // Global, const instance of an empty variant.
-const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
+const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}};
 
 ScopedVariant::~ScopedVariant() {
   COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
@@ -82,7 +82,7 @@
 }
 
 VARIANT ScopedVariant::Copy() const {
-  VARIANT ret = { VT_EMPTY };
+  VARIANT ret = {{{VT_EMPTY}}};
   ::VariantCopy(&ret, &var_);
   return ret;
 }
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
index f8b2182..57f8e61 100644
--- a/base/win/shortcut.cc
+++ b/base/win/shortcut.cc
@@ -5,13 +5,18 @@
 #include "base/win/shortcut.h"
 
 #include <shellapi.h>
+#include <shldisp.h>
 #include <shlobj.h>
 #include <propkey.h>
 
 #include "base/files/file_util.h"
+#include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_bstr.h"
 #include "base/win/scoped_comptr.h"
+#include "base/win/scoped_handle.h"
 #include "base/win/scoped_propvariant.h"
+#include "base/win/scoped_variant.h"
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 
@@ -20,6 +25,90 @@
 
 namespace {
 
+// String resource IDs in shell32.dll.
+const uint32_t kPinToTaskbarID = 5386;
+const uint32_t kUnpinFromTaskbarID = 5387;
+
+// Traits for a GenericScopedHandle that will free a module on closure.
+struct ModuleTraits {
+  typedef HMODULE Handle;
+  static Handle NullHandle() { return nullptr; }
+  static bool IsHandleValid(Handle module) { return !!module; }
+  static bool CloseHandle(Handle module) { return !!::FreeLibrary(module); }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleTraits);
+};
+
+// An object that will free a module when it goes out of scope.
+using ScopedLibrary = GenericScopedHandle<ModuleTraits, DummyVerifierTraits>;
+
+// Returns the shell resource string identified by |resource_id|, or an empty
+// string on error.
+string16 LoadShellResourceString(uint32_t resource_id) {
+  ScopedLibrary shell32(::LoadLibrary(L"shell32.dll"));
+  if (!shell32.IsValid())
+    return string16();
+
+  const wchar_t* resource_ptr = nullptr;
+  int length = ::LoadStringW(shell32.Get(), resource_id,
+                             reinterpret_cast<wchar_t*>(&resource_ptr), 0);
+  if (!length || !resource_ptr)
+    return string16();
+  return string16(resource_ptr, length);
+}
+
+// Uses the shell to perform the verb identified by |resource_id| on |path|.
+bool DoVerbOnFile(uint32_t resource_id, const FilePath& path) {
+  string16 verb_name(LoadShellResourceString(resource_id));
+  if (verb_name.empty())
+    return false;
+
+  ScopedComPtr<IShellDispatch> shell_dispatch;
+  HRESULT hresult =
+      shell_dispatch.CreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER);
+  if (FAILED(hresult) || !shell_dispatch.get())
+    return false;
+
+  ScopedComPtr<Folder> folder;
+  hresult = shell_dispatch->NameSpace(
+      ScopedVariant(path.DirName().value().c_str()), folder.Receive());
+  if (FAILED(hresult) || !folder.get())
+    return false;
+
+  ScopedComPtr<FolderItem> item;
+  hresult = folder->ParseName(ScopedBstr(path.BaseName().value().c_str()),
+                              item.Receive());
+  if (FAILED(hresult) || !item.get())
+    return false;
+
+  ScopedComPtr<FolderItemVerbs> verbs;
+  hresult = item->Verbs(verbs.Receive());
+  if (FAILED(hresult) || !verbs.get())
+    return false;
+
+  long verb_count = 0;
+  hresult = verbs->get_Count(&verb_count);
+  if (FAILED(hresult))
+    return false;
+
+  for (long i = 0; i < verb_count; ++i) {
+    ScopedComPtr<FolderItemVerb> verb;
+    hresult = verbs->Item(ScopedVariant(i, VT_I4), verb.Receive());
+    if (FAILED(hresult) || !verb.get())
+      continue;
+    ScopedBstr name;
+    hresult = verb->get_Name(name.Receive());
+    if (FAILED(hresult))
+      continue;
+    if (StringPiece16(name, name.Length()) == verb_name) {
+      hresult = verb->DoIt();
+      return SUCCEEDED(hresult);
+    }
+  }
+  return false;
+}
+
 // Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
 // are already initialized).
 // If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
@@ -314,28 +403,24 @@
   return true;
 }
 
-bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+bool TaskbarPinShortcutLink(const FilePath& shortcut) {
   base::ThreadRestrictions::AssertIOAllowed();
 
   // "Pin to taskbar" is only supported after Win7.
   if (GetVersion() < VERSION_WIN7)
     return false;
 
-  intptr_t result = reinterpret_cast<intptr_t>(
-      ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
-  return result > 32;
+  return DoVerbOnFile(kPinToTaskbarID, shortcut);
 }
 
-bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+bool TaskbarUnpinShortcutLink(const FilePath& shortcut) {
   base::ThreadRestrictions::AssertIOAllowed();
 
   // "Unpin from taskbar" is only supported after Win7.
   if (GetVersion() < VERSION_WIN7)
     return false;
 
-  intptr_t result = reinterpret_cast<intptr_t>(
-      ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
-  return result > 32;
+  return DoVerbOnFile(kUnpinFromTaskbarID, shortcut);
 }
 
 }  // namespace win
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
index 6f7d10c..6c85f01 100644
--- a/base/win/shortcut.h
+++ b/base/win/shortcut.h
@@ -155,12 +155,12 @@
 // Pins a shortcut to the Windows 7 taskbar. The shortcut file must already
 // exist and be a shortcut that points to an executable. The app id of the
 // shortcut is used to group windows and must be set correctly.
-BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut);
+BASE_EXPORT bool TaskbarPinShortcutLink(const FilePath& shortcut);
 
 // Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
 // already be pinned to the taskbar. The app id of the shortcut is used as the
 // identifier for the taskbar item to remove and must be set correctly.
-BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut);
+BASE_EXPORT bool TaskbarUnpinShortcutLink(const FilePath& shortcut);
 
 }  // namespace win
 }  // namespace base
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index c5b06c4..7b4f612 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -19,11 +19,14 @@
 #include <signal.h>
 #include <stdlib.h>
 
+#include "base/base_switches.h"
+#include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/win/metro.h"
 #include "base/win/registry.h"
@@ -32,13 +35,16 @@
 #include "base/win/scoped_propvariant.h"
 #include "base/win/windows_version.h"
 
+namespace base {
+namespace win {
+
 namespace {
 
 // Sets the value of |property_key| to |property_value| in |property_store|.
 bool SetPropVariantValueForPropertyStore(
     IPropertyStore* property_store,
     const PROPERTYKEY& property_key,
-    const base::win::ScopedPropVariant& property_value) {
+    const ScopedPropVariant& property_value) {
   DCHECK(property_store);
 
   HRESULT result = property_store->SetValue(property_key, property_value.get());
@@ -48,31 +54,56 @@
 }
 
 void __cdecl ForceCrashOnSigAbort(int) {
-  *((int*)0) = 0x1337;
+  *((volatile int*)0) = 0x1337;
 }
 
 const wchar_t kWindows8OSKRegPath[] =
     L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
     L"\\LocalServer32";
 
+}  // namespace
+
 // Returns true if a physical keyboard is detected on Windows 8 and up.
 // Uses the Setup APIs to enumerate the attached keyboards and returns true
 // if the keyboard count is 1 or more.. While this will work in most cases
 // it won't work if there are devices which expose keyboard interfaces which
 // are attached to the machine.
-bool IsKeyboardPresentOnSlate() {
+bool IsKeyboardPresentOnSlate(std::string* reason) {
+  bool result = false;
+
+  if (GetVersion() < VERSION_WIN7) {
+    *reason = "Detection not supported";
+    return false;
+  }
+
   // This function is only supported for Windows 8 and up.
-  DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN8);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableUsbKeyboardDetect)) {
+    if (reason)
+      *reason = "Detection disabled";
+    return false;
+  }
 
   // This function should be only invoked for machines with touch screens.
   if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
         != NID_INTEGRATED_TOUCH) {
-    return true;
+    if (reason) {
+      *reason += "NID_INTEGRATED_TOUCH\n";
+      result = true;
+    } else {
+      return true;
+    }
   }
 
   // If the device is docked, the user is treating the device as a PC.
-  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
-    return true;
+  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
+    if (reason) {
+      *reason += "SM_SYSTEMDOCKED\n";
+      result = true;
+    } else {
+      return true;
+    }
+  }
 
   // To determine whether a keyboard is present on the device, we do the
   // following:-
@@ -103,7 +134,13 @@
       // If there is no auto rotation sensor or rotation is not supported in
       // the current configuration, then we can assume that this is a desktop
       // or a traditional laptop.
-      return true;
+      if (reason) {
+        *reason += (auto_rotation_state & AR_NOSENSOR) ? "AR_NOSENSOR\n"
+                                                       : "AR_NOT_SUPPORTED\n";
+        result = true;
+      } else {
+        return true;
+      }
     }
   }
 
@@ -114,8 +151,15 @@
   POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
 
   if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
-       (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0))
-    return false;
+      (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0)) {
+    if (reason) {
+      *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n"
+                                              : "PlatformRoleSlate\n";
+      // Don't change result here if it's already true.
+    } else {
+      return false;
+    }
+  }
 
   const GUID KEYBOARD_CLASS_GUID =
       { 0x4D36E96B, 0xE325,  0x11CE,
@@ -124,13 +168,15 @@
   // Query for all the keyboard devices.
   HDEVINFO device_info =
       SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, NULL, NULL, DIGCF_PRESENT);
-  if (device_info == INVALID_HANDLE_VALUE)
-    return false;
+  if (device_info == INVALID_HANDLE_VALUE) {
+    if (reason)
+      *reason += "No keyboard info\n";
+    return result;
+  }
 
   // Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If
   // the count is more than 1 we assume that a keyboard is present. This is
   // under the assumption that there will always be one keyboard device.
-  int keyboard_count = 0;
   for (DWORD i = 0;; ++i) {
     SP_DEVINFO_DATA device_info_data = { 0 };
     device_info_data.cbSize = sizeof(device_info_data);
@@ -146,23 +192,24 @@
     if (status == CR_SUCCESS) {
       // To reduce the scope of the hack we only look for ACPI and HID\\VID
       // prefixes in the keyboard device ids.
-      if (StartsWith(device_id, L"ACPI", false) ||
-          StartsWith(device_id, L"HID\\VID", false)) {
-        keyboard_count++;
+      if (StartsWith(device_id, L"ACPI", CompareCase::INSENSITIVE_ASCII) ||
+          StartsWith(device_id, L"HID\\VID", CompareCase::INSENSITIVE_ASCII)) {
+        if (reason) {
+          *reason += "device: ";
+          *reason += WideToUTF8(device_id);
+          *reason += '\n';
+        }
+        // The heuristic we are using is to check the count of keyboards and
+        // return true if the API's report one or more keyboards. Please note
+        // that this will break for non keyboard devices which expose a
+        // keyboard PDO.
+        result = true;
       }
     }
   }
-  // The heuristic we are using is to check the count of keyboards and return
-  // true if the API's report one or more keyboards. Please note that this
-  // will break for non keyboard devices which expose a keyboard PDO.
-  return keyboard_count >= 1;
+  return result;
 }
 
-}  // namespace
-
-namespace base {
-namespace win {
-
 static bool g_crash_on_process_detach = false;
 
 void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) {
@@ -181,7 +228,7 @@
   HANDLE token = NULL;
   if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
     return false;
-  base::win::ScopedHandle token_scoped(token);
+  ScopedHandle token_scoped(token);
 
   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
   scoped_ptr<BYTE[]> user_bytes(new BYTE[size]);
@@ -226,11 +273,11 @@
   // This can be slow if Windows ends up going to disk.  Should watch this key
   // for changes and only read it once, preferably on the file thread.
   //   http://code.google.com/p/chromium/issues/detail?id=61644
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ThreadRestrictions::ScopedAllowIO allow_io;
 
-  base::win::RegKey key(HKEY_LOCAL_MACHINE,
-      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
-      KEY_READ);
+  RegKey key(HKEY_LOCAL_MACHINE,
+             L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
+             KEY_READ);
   DWORD uac_enabled;
   if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
     return true;
@@ -284,20 +331,20 @@
 
 bool AddCommandToAutoRun(HKEY root_key, const string16& name,
                          const string16& command) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
   return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
       ERROR_SUCCESS);
 }
 
 bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
   return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
 }
 
 bool ReadCommandFromAutoRun(HKEY root_key,
                             const string16& name,
                             string16* command) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
   return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
 }
 
@@ -326,8 +373,8 @@
   if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
     return false;
 
-  base::win::Version version = base::win::GetVersion();
-  if (version == base::win::VERSION_XP)
+  Version version = GetVersion();
+  if (version == VERSION_XP)
     return (GetSystemMetrics(SM_TABLETPC) != 0);
 
   // If the device is docked, the user is treating the device as a PC.
@@ -339,7 +386,7 @@
   POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
   bool mobile_power_profile = (role == PlatformRoleMobile);
   bool slate_power_profile = false;
-  if (version >= base::win::VERSION_WIN8)
+  if (version >= VERSION_WIN8)
     slate_power_profile = (role == PlatformRoleSlate);
 
   if (mobile_power_profile || slate_power_profile)
@@ -349,14 +396,13 @@
 }
 
 bool DisplayVirtualKeyboard() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (GetVersion() < VERSION_WIN8)
     return false;
 
-  if (IsKeyboardPresentOnSlate())
+  if (IsKeyboardPresentOnSlate(nullptr))
     return false;
 
-  static base::LazyInstance<string16>::Leaky osk_path =
-      LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<string16>::Leaky osk_path = LAZY_INSTANCE_INITIALIZER;
 
   if (osk_path.Get().empty()) {
     // We need to launch TabTip.exe from the location specified under the
@@ -367,9 +413,8 @@
     // We don't want to launch TabTip.exe from
     // c:\program files (x86)\common files\microsoft shared\ink. This path is
     // normally found on 64 bit Windows.
-    base::win::RegKey key(HKEY_LOCAL_MACHINE,
-                          kWindows8OSKRegPath,
-                          KEY_READ | KEY_WOW64_64KEY);
+    RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath,
+               KEY_READ | KEY_WOW64_64KEY);
     DWORD osk_path_length = 1024;
     if (key.ReadValue(NULL,
                       WriteInto(&osk_path.Get(), osk_path_length),
@@ -410,7 +455,7 @@
         common_program_files_path = common_program_files_wow6432.get();
         DCHECK(!common_program_files_path.empty());
       } else {
-        base::win::ScopedCoMem<wchar_t> common_program_files;
+        ScopedCoMem<wchar_t> common_program_files;
         if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
                                         &common_program_files))) {
           return false;
@@ -432,7 +477,7 @@
 }
 
 bool DismissVirtualKeyboard() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (GetVersion() < VERSION_WIN8)
     return false;
 
   // We dismiss the virtual keyboard by generating the ESC keystroke
@@ -474,21 +519,21 @@
 }
 
 bool MaybeHasSHA256Support() {
-  const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+  const OSInfo* os_info = OSInfo::GetInstance();
 
-  if (os_info->version() == base::win::VERSION_PRE_XP)
+  if (os_info->version() == VERSION_PRE_XP)
     return false;  // Too old to have it and this OS is not supported anyway.
 
-  if (os_info->version() == base::win::VERSION_XP)
+  if (os_info->version() == VERSION_XP)
     return os_info->service_pack().major >= 3;  // Windows XP SP3 has it.
 
   // Assume it is missing in this case, although it may not be. This category
   // includes Windows XP x64, and Windows Server, where a hotfix could be
   // deployed.
-  if (os_info->version() == base::win::VERSION_SERVER_2003)
+  if (os_info->version() == VERSION_SERVER_2003)
     return false;
 
-  DCHECK(os_info->version() >= base::win::VERSION_VISTA);
+  DCHECK(os_info->version() >= VERSION_VISTA);
   return true;  // New enough to have SHA-256 support.
 }
 
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 8513f62..9f42e44 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -132,6 +132,11 @@
 // insight into how users use Chrome.
 BASE_EXPORT bool IsTabletDevice();
 
+// A slate is a touch device that may have a keyboard attached. This function
+// returns true if a keyboard is attached and optionally will set the reason
+// parameter to the detection method that was used to detect the keyboard.
+BASE_EXPORT bool IsKeyboardPresentOnSlate(std::string* reason);
+
 // Get the size of a struct up to and including the specified member.
 // This is necessary to set compatible struct sizes for different versions
 // of certain Windows APIs (e.g. SystemParametersInfo).
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
index fc2def3..35cdbb3 100644
--- a/base/win/windows_version.cc
+++ b/base/win/windows_version.cc
@@ -73,7 +73,7 @@
   service_pack_.major = version_info.wServicePackMajor;
   service_pack_.minor = version_info.wServicePackMinor;
 
-  SYSTEM_INFO system_info = { 0 };
+  SYSTEM_INFO system_info = {};
   ::GetNativeSystemInfo(&system_info);
   switch (system_info.wProcessorArchitecture) {
     case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break;
diff --git a/crypto/random_unittest.cc b/crypto/random_unittest.cc
index 846d9b6..00d4b2b 100644
--- a/crypto/random_unittest.cc
+++ b/crypto/random_unittest.cc
@@ -22,6 +22,6 @@
 
 TEST(RandBytes, RandBytes) {
   std::string bytes(16, '\0');
-  crypto::RandBytes(WriteInto(&bytes, bytes.size()), bytes.size());
+  crypto::RandBytes(base::WriteInto(&bytes, bytes.size()), bytes.size());
   EXPECT_TRUE(!IsTrivial(bytes));
 }
diff --git a/gin/modules/console.cc b/gin/modules/console.cc
index d172373..e471312 100644
--- a/gin/modules/console.cc
+++ b/gin/modules/console.cc
@@ -6,6 +6,7 @@
 
 #include <iostream>
 
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "gin/arguments.h"
 #include "gin/converter.h"
@@ -25,7 +26,7 @@
     args->ThrowError();
     return;
   }
-  std::cout << JoinString(messages, ' ') << std::endl;
+  std::cout << base::JoinString(messages, " ") << std::endl;
 }
 
 WrapperInfo g_wrapper_info = { kEmbedderNativeGin };
diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc
index 99c928c..9d2d6b2 100644
--- a/gin/per_isolate_data.cc
+++ b/gin/per_isolate_data.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "gin/per_isolate_data.h"
 #include "gin/public/gin_embedders.h"
 
@@ -21,7 +22,7 @@
                                ArrayBuffer::Allocator* allocator)
     : isolate_(isolate),
       allocator_(allocator),
-      message_loop_proxy_(base::MessageLoopProxy::current()) {
+      task_runner_(base::MessageLoop::current()->task_runner()) {
   isolate_->SetData(kEmbedderNativeGin, this);
 }
 
diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h
index bffe5fb..175161c 100644
--- a/gin/per_isolate_data.h
+++ b/gin/per_isolate_data.h
@@ -14,7 +14,7 @@
 #include "v8/include/v8.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace gin {
@@ -65,9 +65,7 @@
 
   v8::Isolate* isolate() { return isolate_; }
   v8::ArrayBuffer::Allocator* allocator() { return allocator_; }
-  base::MessageLoopProxy* message_loop_proxy() {
-    return message_loop_proxy_.get();
-  }
+  base::SingleThreadTaskRunner* task_runner() { return task_runner_.get(); }
 
  private:
   typedef std::map<
@@ -87,7 +85,7 @@
   FunctionTemplateMap function_templates_;
   IndexedPropertyInterceptorMap indexed_interceptors_;
   NamedPropertyInterceptorMap named_interceptors_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(PerIsolateData);
 };
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index c8ee770..244534f 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/threading/thread.h"
 #include "gin/per_isolate_data.h"
 
@@ -32,13 +31,12 @@
     background_thread_.reset(new base::Thread("gin_background"));
     background_thread_->Start();
   }
-  background_thread_->message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&v8::Task::Run, base::Owned(task)));
+  background_thread_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&v8::Task::Run, base::Owned(task)));
 }
 
 void V8Platform::CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) {
-  PerIsolateData::From(isolate)->message_loop_proxy()->PostTask(
+  PerIsolateData::From(isolate)->task_runner()->PostTask(
       FROM_HERE, base::Bind(&v8::Task::Run, base::Owned(task)));
 }
 
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
index 977822e..c612644 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
@@ -88,10 +88,11 @@
 class TransferThread : public base::Thread {
  public:
   TransferThread() : base::Thread(kAsyncTransferThreadName) {
-    Start();
+    base::Thread::Options options;
 #if defined(OS_ANDROID) || defined(OS_LINUX)
-    SetPriority(base::ThreadPriority::BACKGROUND);
+    options.priority = base::ThreadPriority::BACKGROUND;
 #endif
+    StartWithOptions(options);
   }
   ~TransferThread() override { Stop(); }
 
@@ -122,8 +123,8 @@
 base::LazyInstance<TransferThread>
     g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
 
-base::MessageLoopProxy* transfer_message_loop_proxy() {
-  return g_transfer_thread.Pointer()->message_loop_proxy().get();
+base::TaskRunner* transfer_task_runner() {
+  return g_transfer_thread.Pointer()->task_runner().get();
 }
 
 // Class which holds async pixel transfers state (EGLImage).
@@ -353,8 +354,8 @@
       eglDestroyImageKHR(display, egl_image_);
     }
     if (thread_texture_id_) {
-      transfer_message_loop_proxy()->PostTask(FROM_HERE,
-          base::Bind(&DeleteTexture, thread_texture_id_));
+      transfer_task_runner()->PostTask(
+          FROM_HERE, base::Bind(&DeleteTexture, thread_texture_id_));
     }
   }
 
@@ -466,16 +467,8 @@
 
 void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion() {
   if (state_->TransferIsInProgress()) {
-#if defined(OS_ANDROID) || defined(OS_LINUX)
-    g_transfer_thread.Pointer()->SetPriority(base::ThreadPriority::BACKGROUND);
-#endif
-
     state_->WaitForTransferCompletion();
     DCHECK(!state_->TransferIsInProgress());
-
-#if defined(OS_ANDROID) || defined(OS_LINUX)
-    g_transfer_thread.Pointer()->SetPriority(base::ThreadPriority::BACKGROUND);
-#endif
   }
 }
 
@@ -501,13 +494,10 @@
 
   // Duplicate the shared memory so there is no way we can get
   // a use-after-free of the raw pixels.
-  transfer_message_loop_proxy()->PostTask(FROM_HERE,
-      base::Bind(
-          &TransferStateInternal::PerformAsyncTexImage2D,
-          state_,
-          tex_params,
-          mem_params,
-          shared_state_->texture_upload_stats));
+  transfer_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&TransferStateInternal::PerformAsyncTexImage2D, state_,
+                 tex_params, mem_params, shared_state_->texture_upload_stats));
 
   DCHECK(CHECK_GL());
 }
@@ -533,13 +523,10 @@
 
   // Duplicate the shared memory so there are no way we can get
   // a use-after-free of the raw pixels.
-  transfer_message_loop_proxy()->PostTask(FROM_HERE,
-      base::Bind(
-          &TransferStateInternal::PerformAsyncTexSubImage2D,
-          state_,
-          tex_params,
-          mem_params,
-          shared_state_->texture_upload_stats));
+  transfer_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&TransferStateInternal::PerformAsyncTexSubImage2D, state_,
+                 tex_params, mem_params, shared_state_->texture_upload_stats));
 
   DCHECK(CHECK_GL());
 }
@@ -702,11 +689,9 @@
     AsyncPixelTransferCompletionObserver* observer) {
   // Post a PerformNotifyCompletion task to the upload thread. This task
   // will run after all async transfers are complete.
-  transfer_message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&PerformNotifyCompletion,
-                 mem_params,
-                 make_scoped_refptr(observer)));
+  transfer_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&PerformNotifyCompletion, mem_params,
+                            make_scoped_refptr(observer)));
 }
 
 uint32 AsyncPixelTransferManagerEGL::GetTextureUploadCount() {
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
index 45e5e5c..eb007bc 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/cancellation_flag.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
@@ -45,10 +46,12 @@
   TransferThread()
       : base::Thread(kAsyncTransferThreadName),
         initialized_(false) {
+    base::Thread::Options options;
     Start();
 #if defined(OS_ANDROID) || defined(OS_LINUX)
-    SetPriority(base::ThreadPriority::BACKGROUND);
+    options.priority = base::ThreadPriority::BACKGROUND;
 #endif
+    StartWithOptions(options);
   }
 
   ~TransferThread() override {
@@ -62,12 +65,11 @@
       return;
 
     base::WaitableEvent wait_for_init(true, false);
-    message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&TransferThread::InitializeOnTransferThread,
-                 base::Unretained(this),
-                 base::Unretained(parent_context),
-                 &wait_for_init));
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&TransferThread::InitializeOnTransferThread,
+                   base::Unretained(this), base::Unretained(parent_context),
+                   &wait_for_init));
     wait_for_init.Wait();
   }
 
@@ -124,8 +126,8 @@
 base::LazyInstance<TransferThread>::Leaky
     g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
 
-base::MessageLoopProxy* transfer_message_loop_proxy() {
-  return g_transfer_thread.Pointer()->message_loop_proxy().get();
+base::SingleThreadTaskRunner* transfer_task_runner() {
+  return g_transfer_thread.Pointer()->task_runner().get();
 }
 
 class PendingTask : public base::RefCountedThreadSafe<PendingTask> {
@@ -247,10 +249,9 @@
         tex_params,
         mem_params,
         texture_upload_stats));
-    transfer_message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &PendingTask::BindAndRun, pending_upload_task_, texture_id_));
+    transfer_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&PendingTask::BindAndRun, pending_upload_task_,
+                              texture_id_));
 
     // Save the late bind callback, so we can notify the client when it is
     // bound.
@@ -268,10 +269,9 @@
         tex_params,
         mem_params,
         texture_upload_stats));
-    transfer_message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &PendingTask::BindAndRun, pending_upload_task_, texture_id_));
+    transfer_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&PendingTask::BindAndRun, pending_upload_task_,
+                              texture_id_));
   }
 
  private:
@@ -506,11 +506,9 @@
     AsyncPixelTransferCompletionObserver* observer) {
   // Post a PerformNotifyCompletion task to the upload thread. This task
   // will run after all async transfers are complete.
-  transfer_message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&PerformNotifyCompletion,
-                 mem_params,
-                 make_scoped_refptr(observer)));
+  transfer_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&PerformNotifyCompletion, mem_params,
+                            make_scoped_refptr(observer)));
 }
 
 uint32 AsyncPixelTransferManagerShareGroup::GetTextureUploadCount() {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index f28a8fb..8caca94 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -51,8 +51,8 @@
   }
 
   void Init(const std::string& str) {
-    std::vector<std::string> tokens;
-    Tokenize(str, " ", &tokens);
+    std::vector<std::string> tokens = base::SplitString(
+        str, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
     string_set_.insert(tokens.begin(), tokens.end());
   }
 
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 2036ed0..f1b9b29 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -14,7 +14,6 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/sequence_checker.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/threading/thread.h"
@@ -956,12 +955,13 @@
 
 namespace {
 
-void PostCallback(const scoped_refptr<base::MessageLoopProxy>& loop,
-                         const base::Closure& callback) {
-  // The loop.get() check is to support using InProcessCommandBuffer on a thread
-  // without a message loop.
-  if (loop.get() && !loop->BelongsToCurrentThread()) {
-    loop->PostTask(FROM_HERE, callback);
+void PostCallback(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const base::Closure& callback) {
+  // The task_runner.get() check is to support using InProcessCommandBuffer on a
+  // thread without a message loop.
+  if (task_runner.get() && !task_runner->BelongsToCurrentThread()) {
+    task_runner->PostTask(FROM_HERE, callback);
   } else {
     callback.Run();
   }
@@ -982,7 +982,7 @@
   base::Closure callback_on_client_thread =
       base::Bind(&RunOnTargetThread, base::Passed(&scoped_callback));
   base::Closure wrapped_callback =
-      base::Bind(&PostCallback, base::MessageLoopProxy::current(),
+      base::Bind(&PostCallback, base::MessageLoop::current()->task_runner(),
                  callback_on_client_thread);
   return wrapped_callback;
 }
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 9187c88..0fd414a 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -782,7 +782,8 @@
       found = uniform->findInfoByMappedName(name, &info, original_name);
     if (found) {
       const std::string kArraySpec("[0]");
-      if (info->arraySize > 0 && !EndsWith(name, kArraySpec, true)) {
+      if (info->arraySize > 0 &&
+          !base::EndsWith(name, kArraySpec, base::CompareCase::SENSITIVE)) {
         *corrected_name = name + kArraySpec;
         *original_name += kArraySpec;
       } else {
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index 6ea07f2..eaa2e61 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -1015,7 +1015,7 @@
 
     gl_type = kGLTypeGLES;
     if (segments.size() > 3 &&
-        StartsWithASCII(segments[3], "(ANGLE", false)) {
+        base::StartsWithASCII(segments[3], "(ANGLE", false)) {
       gl_type = kGLTypeANGLE;
     }
   } else {
diff --git a/gpu/config/gpu_info_collector_linux.cc b/gpu/config/gpu_info_collector_linux.cc
index 023c08b..413e949 100644
--- a/gpu/config/gpu_info_collector_linux.cc
+++ b/gpu/config/gpu_info_collector_linux.cc
@@ -56,7 +56,7 @@
   base::StringTokenizer t(contents, "\r\n");
   while (t.GetNext()) {
     std::string line = t.token();
-    if (StartsWithASCII(line, "ReleaseVersion=", true)) {
+    if (base::StartsWithASCII(line, "ReleaseVersion=", true)) {
       size_t begin = line.find_first_of("0123456789");
       if (begin != std::string::npos) {
         size_t end = line.find_first_not_of("0123456789.", begin);
@@ -244,7 +244,7 @@
   DCHECK(gpu_info);
 
   std::string gl_version = gpu_info->gl_version;
-  if (StartsWithASCII(gl_version, "OpenGL ES", true))
+  if (base::StartsWithASCII(gl_version, "OpenGL ES", true))
     gl_version = gl_version.substr(10);
   std::vector<std::string> pieces;
   base::SplitStringAlongWhitespace(gl_version, &pieces);
diff --git a/gpu/config/gpu_test_expectations_parser.cc b/gpu/config/gpu_test_expectations_parser.cc
index dec42c5..9a6e191 100644
--- a/gpu/config/gpu_test_expectations_parser.cc
+++ b/gpu/config/gpu_test_expectations_parser.cc
@@ -129,9 +129,9 @@
 };
 
 Token ParseToken(const std::string& word) {
-  if (StartsWithASCII(word, "//", false))
+  if (base::StartsWithASCII(word, "//", false))
     return kTokenComment;
-  if (StartsWithASCII(word, "0x", false))
+  if (base::StartsWithASCII(word, "0x", false))
     return kConfigGPUDeviceID;
 
   for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
diff --git a/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java b/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
index 4af9a28..6edf95f 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
@@ -25,8 +25,9 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
-        nativeInitApplicationContext(getInstrumentation().getTargetContext());
+        Context context = getInstrumentation().getTargetContext();
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(context);
+        nativeInitApplicationContext(context);
         mTestEnvironmentPointer = nativeSetupTestEnvironment();
     }
 
diff --git a/mojo/dart/embedder/dart_controller.cc b/mojo/dart/embedder/dart_controller.cc
index 98e2688..e3779a1 100644
--- a/mojo/dart/embedder/dart_controller.cc
+++ b/mojo/dart/embedder/dart_controller.cc
@@ -264,7 +264,7 @@
                                               Dart_Handle url) {
   if (tag == Dart_kCanonicalizeUrl) {
     std::string string = tonic::StdStringFromDart(url);
-    if (StartsWithASCII(string, "dart:", true))
+    if (base::StartsWith(string, "dart:", base::CompareCase::SENSITIVE))
       return url;
   }
   return tonic::DartLibraryLoader::HandleLibraryTag(tag, library, url);
@@ -451,7 +451,8 @@
 
   // If it's a file URI, strip the scheme.
   const char* file_scheme = "file://";
-  if (StartsWithASCII(script_uri_string, file_scheme, true)) {
+  if (base::StartsWith(script_uri_string, file_scheme,
+                       base::CompareCase::SENSITIVE)) {
     script_uri_string = script_uri_string.substr(strlen(file_scheme));
   }
 
diff --git a/mojo/dart/unittests/embedder_tester/validation_unittest.cc b/mojo/dart/unittests/embedder_tester/validation_unittest.cc
index 1300ca9..74674ad 100644
--- a/mojo/dart/unittests/embedder_tester/validation_unittest.cc
+++ b/mojo/dart/unittests/embedder_tester/validation_unittest.cc
@@ -79,7 +79,8 @@
       std::string source;
       bool r;
       std::string filename = base::FilePath(test_name).BaseName().value();
-      if (!StartsWithASCII(filename, "conformance_", true)) {
+      if (!base::StartsWith(filename, "conformance_",
+                            base::CompareCase::SENSITIVE)) {
         // Only include conformance tests.
         continue;
       }
diff --git a/services/authenticating_url_loader_interceptor/authenticating_url_loader_interceptor_apptest.cc b/services/authenticating_url_loader_interceptor/authenticating_url_loader_interceptor_apptest.cc
index 9bf7aa2..4f4a9a8 100644
--- a/services/authenticating_url_loader_interceptor/authenticating_url_loader_interceptor_apptest.cc
+++ b/services/authenticating_url_loader_interceptor/authenticating_url_loader_interceptor_apptest.cc
@@ -7,7 +7,7 @@
 #include "base/atomic_sequence_num.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/strings/string_util.h"
+#include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "mojo/public/cpp/application/application_connection.h"
 #include "mojo/public/cpp/application/application_impl.h"
@@ -206,8 +206,9 @@
       HttpHeaderPtr header = request->headers[0].Pass();
       EXPECT_EQ(kAuthenticationHeaderName, header->name);
 
-      std::vector<std::string> auth_value_components;
-      Tokenize(header->value, " ", &auth_value_components);
+      std::vector<std::string> auth_value_components =
+          base::SplitString(header->value.To<std::string>(), " ",
+                            base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
       EXPECT_EQ(2u, auth_value_components.size());
       if (auth_value_components.size() == 2) {
         EXPECT_EQ(kAuthenticationHeaderValuePrefix, auth_value_components[0]);
diff --git a/services/dart/content_handler_main.cc b/services/dart/content_handler_main.cc
index 4d73d83..84c723a 100644
--- a/services/dart/content_handler_main.cc
+++ b/services/dart/content_handler_main.cc
@@ -5,7 +5,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/strings/string_util.h"
+#include "base/strings/string_split.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "base/trace_event/trace_event.h"
@@ -36,7 +36,7 @@
 static bool IsDartZip(std::string url) {
   // If the url doesn't end with ".dart" we assume it is a zipped up
   // dart application.
-  return !EndsWith(url, ".dart", false);
+  return !base::EndsWith(url, ".dart", base::CompareCase::INSENSITIVE_ASCII);
 }
 
 class DartContentHandlerApp;
@@ -158,8 +158,8 @@
     bool strict_compilation = false;
     GURL url(requestedUrl);
     if (url.has_query()) {
-      std::vector<std::string> query_parameters;
-      Tokenize(url.query(), "&", &query_parameters);
+      std::vector<std::string> query_parameters = base::SplitString(
+          url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
       strict_compilation =
           std::find(query_parameters.begin(), query_parameters.end(),
                     "strict=true") != query_parameters.end();
diff --git a/services/python/content_handler/content_handler_main.cc b/services/python/content_handler/content_handler_main.cc
index d05de8b..1f21f00 100644
--- a/services/python/content_handler/content_handler_main.cc
+++ b/services/python/content_handler/content_handler_main.cc
@@ -8,7 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/i18n/icu_util.h"
-#include "base/strings/string_util.h"
+#include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "mojo/application/application_runner_chromium.h"
 #include "mojo/application/content_handler_factory.h"
@@ -224,8 +224,8 @@
   bool IsDebug(const std::string& requestedUrl) {
     GURL url(requestedUrl);
     if (url.has_query()) {
-      std::vector<std::string> query_parameters;
-      Tokenize(url.query(), "&", &query_parameters);
+      std::vector<std::string> query_parameters = base::SplitString(
+          url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
       return std::find(query_parameters.begin(), query_parameters.end(),
                        "debug=true") != query_parameters.end();
     }
diff --git a/services/url_response_disk_cache/url_response_disk_cache_impl.cc b/services/url_response_disk_cache/url_response_disk_cache_impl.cc
index 7cbca7c..318a469 100644
--- a/services/url_response_disk_cache/url_response_disk_cache_impl.cc
+++ b/services/url_response_disk_cache/url_response_disk_cache_impl.cc
@@ -237,7 +237,8 @@
 
 // Returns whether the given |entry| is valid.
 bool IsCacheEntryValid(const CacheEntryPtr& entry) {
-  return entry && PathExists(base::FilePath(entry->response_body_path));
+  return entry &&
+         PathExists(base::FilePath::FromUTF8Unsafe(entry->response_body_path));
 }
 
 // Returns whether the given directory |entry| is valid and its content can be
@@ -285,7 +286,8 @@
     iterator->GetNext(&key, &entry);
     if (last_key && last_key->request_origin == key->request_origin &&
         last_key->url == key->url) {
-      base::FilePath entry_directory = base::FilePath(entry->entry_directory);
+      base::FilePath entry_directory =
+          base::FilePath::FromUTF8Unsafe(entry->entry_directory);
       if (base::DeleteFile(entry_directory, true))
         db->Delete(key.Clone());
     }
@@ -390,10 +392,11 @@
     callback.Run(URLResponsePtr(), nullptr, nullptr);
     return;
   }
-  callback.Run(entry->response.Pass(),
-               PathToArray(base::FilePath(entry->response_body_path)),
-               PathToArray(GetConsumerCacheDirectory(
-                   base::FilePath(entry->entry_directory))));
+  callback.Run(
+      entry->response.Pass(),
+      PathToArray(base::FilePath::FromUTF8Unsafe(entry->response_body_path)),
+      PathToArray(GetConsumerCacheDirectory(
+          base::FilePath::FromUTF8Unsafe(entry->entry_directory))));
   UpdateLastInvalidation(db_, key.Pass(), base::Time::Now());
 }
 
@@ -441,9 +444,9 @@
   CacheKeyPtr key;
   CacheEntryPtr entry = db_->GetNewest(request_origin_, url, &key);
   if (IsCacheEntryFresh(response, entry)) {
-    callback.Run(
-        base::FilePath(entry->response_body_path),
-        GetConsumerCacheDirectory(base::FilePath(entry->entry_directory)));
+    callback.Run(base::FilePath::FromUTF8Unsafe(entry->response_body_path),
+                 GetConsumerCacheDirectory(
+                     base::FilePath::FromUTF8Unsafe(entry->entry_directory)));
     UpdateLastInvalidation(db_, key.Pass(), base::Time::Max());
     return;
   }
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index 9d5f5bf..879a23e 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -655,6 +655,7 @@
     "//base",
     "//mojo/application",
     "//mojo/application:test_support",
+    "//mojo/converters/base",
     "//mojo/data_pipe_utils",
     "//mojo/public/cpp/bindings:callback",
     "//mojo/public/cpp/environment",
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java b/shell/android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java
index 0dbdeab..5d2f02b 100644
--- a/shell/android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java
+++ b/shell/android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java
@@ -40,7 +40,8 @@
      */
     private void initializeNative() {
         try {
-            LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
+            LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER)
+                    .ensureInitialized(getApplicationContext());
         } catch (ProcessInitException e) {
             Log.e(TAG, "libmojo_shell initialization failed.", e);
             throw new RuntimeException(e);
diff --git a/shell/android/url_response_disk_cache_delegate_impl.cc b/shell/android/url_response_disk_cache_delegate_impl.cc
index 5e7d0ac..badacab 100644
--- a/shell/android/url_response_disk_cache_delegate_impl.cc
+++ b/shell/android/url_response_disk_cache_delegate_impl.cc
@@ -83,7 +83,8 @@
         base::Bind(&AAssetDir_close, base::Unretained(dir)));
     while (const char* filename = AAssetDir_getNextFileName(dir)) {
       std::string file_name_string = filename;
-      if (EndsWith(file_name_string, kMojoApplicationSuffix, true)) {
+      if (base::EndsWith(file_name_string, kMojoApplicationSuffix,
+                         base::CompareCase::SENSITIVE)) {
         std::string base_name = file_name_string.substr(
             0,
             file_name_string.size() - (arraysize(kMojoApplicationSuffix) - 1));
diff --git a/shell/application_manager/application_manager.cc b/shell/application_manager/application_manager.cc
index 77d657d..b4f8876 100644
--- a/shell/application_manager/application_manager.cc
+++ b/shell/application_manager/application_manager.cc
@@ -210,9 +210,11 @@
   // connecting to those apps would result in a recursive loop, so it has to be
   // explicitly avoided here. What this means in practice is that these apps
   // cannot themselves require authentication to obtain.
-  if (EndsWith(resolved_url.path(), "/authentication.mojo", true) ||
-      EndsWith(resolved_url.path(),
-               "/authenticating_url_loader_interceptor.mojo", true)) {
+  if (base::EndsWith(resolved_url.path(), "/authentication.mojo",
+                     base::CompareCase::SENSITIVE) ||
+      base::EndsWith(resolved_url.path(),
+                     "/authenticating_url_loader_interceptor.mojo",
+                     base::CompareCase::SENSITIVE)) {
     network_service = network_service_.get();
   } else if (!initialized_authentication_interceptor_) {
 #ifndef NO_AUTHENTICATION
diff --git a/shell/context.cc b/shell/context.cc
index 6056730..4f0d693 100644
--- a/shell/context.cc
+++ b/shell/context.cc
@@ -150,7 +150,7 @@
   //     (to embed a comma into a string escape it using "\,")
   // Whatever takes 'parameters' and constructs a CommandLine is failing to
   // un-escape the commas, we need to move this fix to that file.
-  ReplaceSubstringsAfterOffset(&handlers_spec, 0, "\\,", ",");
+  base::ReplaceSubstringsAfterOffset(&handlers_spec, 0, "\\,", ",");
 #endif
 
   std::vector<std::string> parts;
@@ -296,7 +296,7 @@
   mojo_shell_child_path_ = shell_child_path;
 
   task_runners_.reset(
-      new TaskRunners(base::MessageLoop::current()->message_loop_proxy()));
+      new TaskRunners(base::MessageLoop::current()->task_runner()));
 
 #if !defined(OS_MACOSX)
   application_manager()->SetLoaderForURL(
diff --git a/shell/crash/crash_upload.cc b/shell/crash/crash_upload.cc
index 17ecc5a..a2316c8 100644
--- a/shell/crash/crash_upload.cc
+++ b/shell/crash/crash_upload.cc
@@ -161,7 +161,7 @@
   // Find multipart boundary.
   std::string start_of_file;
   base::ReadFileToString(minidump, &start_of_file, kMaxBoundarySize);
-  if (!StartsWithASCII(start_of_file, "--", true)) {
+  if (!base::StartsWith(start_of_file, "--", base::CompareCase::SENSITIVE)) {
     LOG(WARNING) << "Corrupted minidump: " << minidump.value();
     base::DeleteFile(minidump, false);
     return MinidumpAndBoundary();
diff --git a/shell/filename_util.cc b/shell/filename_util.cc
index 2dbdd11..936acb0 100644
--- a/shell/filename_util.cc
+++ b/shell/filename_util.cc
@@ -36,21 +36,21 @@
 
   // This must be the first substitution since others will introduce percents as
   // the escape character
-  ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("%"),
-                               FILE_PATH_LITERAL("%25"));
+  base::ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("%"),
+                                     FILE_PATH_LITERAL("%25"));
 
   // A semicolon is supposed to be some kind of separator according to RFC 2396.
-  ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL(";"),
-                               FILE_PATH_LITERAL("%3B"));
+  base::ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL(";"),
+                                     FILE_PATH_LITERAL("%3B"));
 
-  ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("#"),
-                               FILE_PATH_LITERAL("%23"));
+  base::ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("#"),
+                                     FILE_PATH_LITERAL("%23"));
 
-  ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("?"),
-                               FILE_PATH_LITERAL("%3F"));
+  base::ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("?"),
+                                     FILE_PATH_LITERAL("%3F"));
 
-  ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("\\"),
-                               FILE_PATH_LITERAL("%5C"));
+  base::ReplaceSubstringsAfterOffset(&url_string, 0, FILE_PATH_LITERAL("\\"),
+                                     FILE_PATH_LITERAL("%5C"));
 
   return GURL(url_string);
 }
diff --git a/shell/shell_apptest.cc b/shell/shell_apptest.cc
index 2829155..09988e5 100644
--- a/shell/shell_apptest.cc
+++ b/shell/shell_apptest.cc
@@ -10,6 +10,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "mojo/converters/base/base_type_converters.h"
 #include "mojo/data_pipe_utils/data_pipe_utils.h"
 #include "mojo/public/cpp/application/application_impl.h"
 #include "mojo/public/cpp/application/application_test_base.h"
@@ -45,7 +46,8 @@
                      const mojo::Callback<void(http_server::HttpResponsePtr)>&
                          callback) override {
     http_server::HttpResponsePtr response;
-    if (StartsWithASCII(request->relative_url, "/app", true)) {
+    if (base::StartsWith(request->relative_url.To<base::StringPiece>(), "/app",
+                         base::CompareCase::SENSITIVE)) {
       response = http_server::CreateHttpResponse(
           200, std::string(shell::test::kPingable.data,
                            shell::test::kPingable.size));
@@ -188,7 +190,9 @@
   application_impl()->ConnectToService("mojo:pingable_app?foo", &pingable);
   auto callback = [](const String& app_url, const String& connection_url,
                      const String& message) {
-    EXPECT_TRUE(EndsWith(app_url, "/pingable_app.mojo", true));
+    EXPECT_TRUE(base::EndsWith(app_url.To<base::StringPiece>(),
+                               "/pingable_app.mojo",
+                               base::CompareCase::SENSITIVE));
     EXPECT_EQ(app_url.To<std::string>() + "?foo", connection_url);
     EXPECT_EQ("hello", message);
     base::MessageLoop::current()->Quit();
@@ -202,7 +206,9 @@
   ConnectToService(app_connector, "mojo:pingable_app", &pingable);
   auto callback = [](const String& app_url, const String& connection_url,
                      const String& message) {
-    EXPECT_TRUE(EndsWith(app_url, "/pingable_app.mojo", true));
+    EXPECT_TRUE(base::EndsWith(app_url.To<base::StringPiece>(),
+                               "/pingable_app.mojo",
+                               base::CompareCase::SENSITIVE));
     EXPECT_EQ(app_url, connection_url);
     EXPECT_EQ("hello", message);
     base::MessageLoop::current()->Quit();
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java
index 2a2a8dd..b15599c 100644
--- a/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java
@@ -27,11 +27,6 @@
         // Needed by path_utils_unittest.cc
         PathUtils.setPrivateDataDirectorySuffix("chrome", getApplicationContext());
 
-        ResourceExtractor resourceExtractor = ResourceExtractor.get(getApplicationContext());
-        resourceExtractor.setExtractAllPaksAndV8SnapshotForTesting();
-        resourceExtractor.startExtractingResources();
-        resourceExtractor.waitForCompletion();
-
         // Needed by system_monitor_unittest.cc
         PowerMonitor.createForTests(this);
 
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index 59d96da..7df46e7 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "third_party/zlib/google/zip_internal.h"
 
 #if defined(USE_SYSTEM_MINIZIP)
@@ -130,7 +131,8 @@
   original_size_ = raw_file_info.uncompressed_size;
 
   // Directory entries in zip files end with "/".
-  is_directory_ = EndsWith(file_name_in_zip, "/", false);
+  is_directory_ =
+      base::EndsWith(file_name_in_zip, "/", base::CompareCase::SENSITIVE);
 
   // Check the file name here for directory traversal issues.
   is_unsafe_ = file_path_.ReferencesParent();
@@ -144,7 +146,8 @@
 
   // We also consider that the file name is unsafe, if it's absolute.
   // On Windows, IsAbsolute() returns false for paths starting with "/".
-  if (file_path_.IsAbsolute() || StartsWithASCII(file_name_in_zip, "/", false))
+  if (file_path_.IsAbsolute() ||
+      base::StartsWith(file_name_in_zip, "/", base::CompareCase::SENSITIVE))
     is_unsafe_ = true;
 
   // Construct the last modified time. The timezone info is not present in
@@ -355,24 +358,26 @@
   // If this is a directory, just create it and return.
   if (current_entry_info()->is_directory()) {
     if (base::CreateDirectory(output_file_path)) {
-      base::MessageLoopProxy::current()->PostTask(FROM_HERE, success_callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    success_callback);
     } else {
       DVLOG(1) << "Unzip failed: unable to create directory.";
-      base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    failure_callback);
     }
     return;
   }
 
   if (unzOpenCurrentFile(zip_file_) != UNZ_OK) {
     DVLOG(1) << "Unzip failed: unable to open current zip entry.";
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     return;
   }
 
   base::FilePath output_dir_path = output_file_path.DirName();
   if (!base::CreateDirectory(output_dir_path)) {
     DVLOG(1) << "Unzip failed: unable to create containing directory.";
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     return;
   }
 
@@ -382,7 +387,7 @@
   if (!output_file.IsValid()) {
     DVLOG(1) << "Unzip failed: unable to create platform file at "
              << output_file_path.value();
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     return;
   }
 
diff --git a/tonic/dart_library_provider_files.cc b/tonic/dart_library_provider_files.cc
index 133cd57..25a3001 100644
--- a/tonic/dart_library_provider_files.cc
+++ b/tonic/dart_library_provider_files.cc
@@ -62,17 +62,17 @@
 }
 
 std::string DartLibraryProviderFiles::CanonicalizePackageURL(std::string url) {
-  DCHECK(StartsWithASCII(url, "package:", true));
-  ReplaceFirstSubstringAfterOffset(&url, 0, "package:", "");
+  DCHECK(base::StartsWithASCII(url, "package:", true));
+  base::ReplaceFirstSubstringAfterOffset(&url, 0, "package:", "");
   return package_root_.Append(url).AsUTF8Unsafe();
 }
 
 Dart_Handle DartLibraryProviderFiles::CanonicalizeURL(Dart_Handle library,
                                                       Dart_Handle url) {
   std::string string = StdStringFromDart(url);
-  if (StartsWithASCII(string, "dart:", true))
+  if (base::StartsWithASCII(string, "dart:", true))
     return url;
-  if (StartsWithASCII(string, "package:", true))
+  if (base::StartsWithASCII(string, "package:", true))
     return StdStringToDart(CanonicalizePackageURL(string));
   base::FilePath base_path(StdStringFromDart(Dart_LibraryUrl(library)));
   base::FilePath resolved_path = base_path.DirName().Append(string);
diff --git a/tonic/dart_library_provider_network.cc b/tonic/dart_library_provider_network.cc
index 890ca53..635d07e 100644
--- a/tonic/dart_library_provider_network.cc
+++ b/tonic/dart_library_provider_network.cc
@@ -81,11 +81,12 @@
 Dart_Handle DartLibraryProviderNetwork::CanonicalizeURL(Dart_Handle library,
                                                         Dart_Handle url) {
   std::string string = StdStringFromDart(url);
-  if (StartsWithASCII(string, "dart:", true))
+  if (base::StartsWithASCII(string, "dart:", true))
     return url;
   // TODO(abarth): The package root should be configurable.
-  if (StartsWithASCII(string, "package:", true))
-    ReplaceFirstSubstringAfterOffset(&string, 0, "package:", "/packages/");
+  if (base::StartsWithASCII(string, "package:", true))
+    base::ReplaceFirstSubstringAfterOffset(&string, 0, "package:",
+                                           "/packages/");
   GURL library_url(StdStringFromDart(Dart_LibraryUrl(library)));
   GURL resolved_url = library_url.Resolve(string);
   return StdStringToDart(resolved_url.spec());
diff --git a/tools/android/forwarder2/device_controller.cc b/tools/android/forwarder2/device_controller.cc
index a4cb9c7..d831c2a 100644
--- a/tools/android/forwarder2/device_controller.cc
+++ b/tools/android/forwarder2/device_controller.cc
@@ -11,7 +11,6 @@
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/single_thread_task_runner.h"
 #include "tools/android/forwarder2/command.h"
 #include "tools/android/forwarder2/device_listener.h"
@@ -49,16 +48,15 @@
                                    int exit_notifier_fd)
     : host_socket_(host_socket.Pass()),
       exit_notifier_fd_(exit_notifier_fd),
-      construction_task_runner_(base::MessageLoopProxy::current()),
+      construction_task_runner_(base::MessageLoop::current()->task_runner()),
       weak_ptr_factory_(this) {
   host_socket_->AddEventFd(exit_notifier_fd);
 }
 
 void DeviceController::AcceptHostCommandSoon() {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&DeviceController::AcceptHostCommandInternal,
-                 base::Unretained(this)));
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&DeviceController::AcceptHostCommandInternal,
+                            base::Unretained(this)));
 }
 
 void DeviceController::AcceptHostCommandInternal() {
diff --git a/tools/android/forwarder2/device_forwarder_main.cc b/tools/android/forwarder2/device_forwarder_main.cc
index 8b5df26..30da954 100644
--- a/tools/android/forwarder2/device_forwarder_main.cc
+++ b/tools/android/forwarder2/device_forwarder_main.cc
@@ -55,15 +55,13 @@
     // thread. Make sure that it gets deleted on that same thread. Note that
     // DeleteSoon() is not used here since it would imply reading |controller_|
     // from the main thread while it's set on the internal thread.
-    controller_thread_->message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(&ServerDelegate::DeleteControllerOnInternalThread,
-                   base::Unretained(this)));
+    controller_thread_->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ServerDelegate::DeleteControllerOnInternalThread,
+                              base::Unretained(this)));
   }
 
   void DeleteControllerOnInternalThread() {
-    DCHECK(
-        controller_thread_->message_loop_proxy()->RunsTasksOnCurrentThread());
+    DCHECK(controller_thread_->task_runner()->RunsTasksOnCurrentThread());
     controller_.reset();
   }
 
diff --git a/tools/android/forwarder2/device_listener.cc b/tools/android/forwarder2/device_listener.cc
index b48a746..c1b3015 100644
--- a/tools/android/forwarder2/device_listener.cc
+++ b/tools/android/forwarder2/device_listener.cc
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/single_thread_task_runner.h"
 #include "tools/android/forwarder2/command.h"
 #include "tools/android/forwarder2/forwarder.h"
@@ -51,7 +50,7 @@
 }
 
 void DeviceListener::SetAdbDataSocket(scoped_ptr<Socket> adb_data_socket) {
-  thread_.message_loop_proxy()->PostTask(
+  thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&DeviceListener::OnAdbDataSocketReceivedOnInternalThread,
                  base::Unretained(this), base::Passed(&adb_data_socket)));
@@ -65,7 +64,7 @@
       listener_socket_(listener_socket.Pass()),
       host_socket_(host_socket.Pass()),
       listener_port_(port),
-      deletion_task_runner_(base::MessageLoopProxy::current()),
+      deletion_task_runner_(base::MessageLoop::current()->task_runner()),
       thread_("DeviceListener") {
   CHECK(host_socket_.get());
   DCHECK(deletion_task_runner_.get());
@@ -74,10 +73,9 @@
 }
 
 void DeviceListener::AcceptNextClientSoon() {
-  thread_.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&DeviceListener::AcceptClientOnInternalThread,
-                 base::Unretained(this)));
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&DeviceListener::AcceptClientOnInternalThread,
+                            base::Unretained(this)));
 }
 
 void DeviceListener::AcceptClientOnInternalThread() {
diff --git a/tools/android/forwarder2/forwarders_manager.cc b/tools/android/forwarder2/forwarders_manager.cc
index 0c0c904..3148e22 100644
--- a/tools/android/forwarder2/forwarders_manager.cc
+++ b/tools/android/forwarder2/forwarders_manager.cc
@@ -14,8 +14,8 @@
 #include "base/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/task_runner.h"
 #include "tools/android/forwarder2/forwarder.h"
 #include "tools/android/forwarder2/socket.h"
 
@@ -35,7 +35,7 @@
                                                    scoped_ptr<Socket> socket2) {
   // Note that the internal Forwarder vector is populated on the internal thread
   // which is the only thread from which it's accessed.
-  thread_.message_loop_proxy()->PostTask(
+  thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&ForwardersManager::CreateNewForwarderOnInternalThread,
                  base::Unretained(this), base::Passed(&socket1),
@@ -49,19 +49,18 @@
 void ForwardersManager::CreateNewForwarderOnInternalThread(
     scoped_ptr<Socket> socket1,
     scoped_ptr<Socket> socket2) {
-  DCHECK(thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
+  DCHECK(thread_.task_runner()->RunsTasksOnCurrentThread());
   forwarders_.push_back(new Forwarder(socket1.Pass(), socket2.Pass()));
 }
 
 void ForwardersManager::WaitForEventsOnInternalThreadSoon() {
-  thread_.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&ForwardersManager::WaitForEventsOnInternalThread,
-                 base::Unretained(this)));
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&ForwardersManager::WaitForEventsOnInternalThread,
+                            base::Unretained(this)));
 }
 
 void ForwardersManager::WaitForEventsOnInternalThread() {
-  DCHECK(thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
+  DCHECK(thread_.task_runner()->RunsTasksOnCurrentThread());
   fd_set read_fds;
   fd_set write_fds;
 
diff --git a/tools/android/forwarder2/host_controller.cc b/tools/android/forwarder2/host_controller.cc
index 94e63ec..dc70606 100644
--- a/tools/android/forwarder2/host_controller.cc
+++ b/tools/android/forwarder2/host_controller.cc
@@ -79,15 +79,13 @@
       global_exit_notifier_fd_(exit_notifier_fd),
       adb_control_socket_(adb_control_socket.Pass()),
       delete_controller_notifier_(delete_controller_notifier.Pass()),
-      deletion_task_runner_(base::MessageLoopProxy::current()),
-      thread_("HostControllerThread") {
-}
+      deletion_task_runner_(base::MessageLoop::current()->task_runner()),
+      thread_("HostControllerThread") {}
 
 void HostController::ReadNextCommandSoon() {
-  thread_.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&HostController::ReadCommandOnInternalThread,
-                 base::Unretained(this)));
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&HostController::ReadCommandOnInternalThread,
+                            base::Unretained(this)));
 }
 
 void HostController::ReadCommandOnInternalThread() {
diff --git a/tools/android/forwarder2/host_forwarder_main.cc b/tools/android/forwarder2/host_forwarder_main.cc
index 16a7b51..3e08321 100644
--- a/tools/android/forwarder2/host_forwarder_main.cc
+++ b/tools/android/forwarder2/host_forwarder_main.cc
@@ -93,8 +93,7 @@
     if (!thread_.get())
       return;
     // Delete the controllers on the thread they were created on.
-    thread_->message_loop_proxy()->DeleteSoon(
-        FROM_HERE, controllers_.release());
+    thread_->task_runner()->DeleteSoon(FROM_HERE, controllers_.release());
   }
 
   void HandleRequest(const std::string& adb_path,
@@ -104,7 +103,7 @@
                      scoped_ptr<Socket> client_socket) {
     // Lazy initialize so that the CLI process doesn't get this thread created.
     InitOnce();
-    thread_->message_loop_proxy()->PostTask(
+    thread_->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&HostControllersManager::HandleRequestOnInternalThread,
                    base::Unretained(this), adb_path, device_serial, device_port,
@@ -143,7 +142,7 @@
       // then all the controllers (including |controller|) were also deleted.
       return;
     }
-    DCHECK(manager->thread_->message_loop_proxy()->RunsTasksOnCurrentThread());
+    DCHECK(manager->thread_->task_runner()->RunsTasksOnCurrentThread());
     // Note that this will delete |controller| which is owned by the map.
     DeleteRefCountedValueInMap(
         MakeHostControllerMapKey(
diff --git a/tools/android/forwarder2/self_deleter_helper.h b/tools/android/forwarder2/self_deleter_helper.h
index d96903d..51fcff1 100644
--- a/tools/android/forwarder2/self_deleter_helper.h
+++ b/tools/android/forwarder2/self_deleter_helper.h
@@ -13,7 +13,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 
 namespace base {
 
@@ -99,11 +98,10 @@
 
   SelfDeleterHelper(T* self_deleting_object,
                     const DeletionCallback& deletion_callback)
-      : construction_runner_(base::MessageLoopProxy::current()),
+      : construction_runner_(base::MessageLoop::current()->task_runner()),
         self_deleting_object_(self_deleting_object),
         deletion_callback_(deletion_callback),
-        weak_ptr_factory_(this) {
-  }
+        weak_ptr_factory_(this) {}
 
   ~SelfDeleterHelper() {
     DCHECK(construction_runner_->RunsTasksOnCurrentThread());
diff --git a/ui/events/devices/device_util_linux.cc b/ui/events/devices/device_util_linux.cc
index 858ee84..9f1f632 100644
--- a/ui/events/devices/device_util_linux.cc
+++ b/ui/events/devices/device_util_linux.cc
@@ -17,7 +17,9 @@
 InputDeviceType GetInputDeviceTypeFromPath(const base::FilePath& path) {
   DCHECK(!base::MessageLoopForUI::IsCurrent());
   std::string event_node = path.BaseName().value();
-  if (event_node.empty() || !StartsWithASCII(event_node, "event", false))
+  if (event_node.empty() ||
+      !base::StartsWith(event_node, "event",
+                        base::CompareCase::INSENSITIVE_ASCII))
     return InputDeviceType::INPUT_DEVICE_UNKNOWN;
 
   // Find sysfs device path for this device.
diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc
index 5bea3f1..bffa64e 100644
--- a/ui/gl/gl_gl_api_implementation.cc
+++ b/ui/gl/gl_gl_api_implementation.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_implementation.h"
@@ -437,8 +438,8 @@
   DCHECK(real_context->IsCurrent(NULL));
   std::string ext_string(
       reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS)));
-  std::vector<std::string> ext;
-  Tokenize(ext_string, " ", &ext);
+  std::vector<std::string> ext = base::SplitString(
+      ext_string, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
   std::vector<std::string>::iterator it;
   // We can't support GL_EXT_occlusion_query_boolean which is
@@ -448,7 +449,7 @@
   if (it != ext.end())
     ext.erase(it);
 
-  extensions_ = JoinString(ext, " ");
+  extensions_ = base::JoinString(ext, " ");
 }
 
 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
diff --git a/ui/gl/gl_version_info.cc b/ui/gl/gl_version_info.cc
index e2aa0de..375580f 100644
--- a/ui/gl/gl_version_info.cc
+++ b/ui/gl/gl_version_info.cc
@@ -35,7 +35,8 @@
       is_es3 = true;
   }
   if (renderer_str) {
-    is_angle = StartsWithASCII(renderer_str, "ANGLE", true);
+    is_angle =
+        base::StartsWith(renderer_str, "ANGLE", base::CompareCase::SENSITIVE);
   }
 }
 
diff --git a/url/origin.cc b/url/origin.cc
index 8aaa173..cebf5dd 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -4,14 +4,15 @@
 
 #include "url/origin.h"
 
-#include "base/strings/string_util.h"
+#include "base/logging.h"
+#include "base/strings/pattern.h"
 
 namespace url {
 
 Origin::Origin() : string_("null") {}
 
 Origin::Origin(const std::string& origin) : string_(origin) {
-  DCHECK(origin == "null" || MatchPattern(origin, "?*://?*"));
+  DCHECK(origin == "null" || base::MatchPattern(origin, "?*://?*"));
   DCHECK_GT(origin.size(), 0u);
   DCHECK(origin == "file://" || origin[origin.size() - 1] != '/');
 }