Update from https://crrev.com/328418

This includes the switch to libc++ on android.

Fixes outside of the rolled code:

*) ::TestSuite -> base::TestSuite
*) base::ScopedPtrHashMap's second parameter Value->scoped_ptr<Value>
*) re2 std::tr1 changes from upstream libc++ changes
*) tracked_objects:: api changes in mojo/common/task_tracker*

Review URL: https://codereview.chromium.org/1128733002
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 2db7261..e7985ef 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -108,6 +108,8 @@
     "android/library_loader/library_load_from_apk_status_codes.h",
     "android/library_loader/library_loader_hooks.cc",
     "android/library_loader/library_loader_hooks.h",
+    "android/library_loader/library_prefetcher.cc",
+    "android/library_loader/library_prefetcher.h",
     "android/locale_utils.cc",
     "android/locale_utils.h",
     "android/memory_pressure_listener_android.cc",
@@ -174,6 +176,7 @@
     "containers/hash_tables.h",
     "containers/linked_list.h",
     "containers/mru_cache.h",
+    "containers/scoped_ptr_hash_map.h",
     "containers/small_map.h",
     "containers/stack_container.h",
     "cpu.cc",
@@ -280,6 +283,8 @@
     "mac/mac_util.mm",
     "mac/mach_logging.cc",
     "mac/mach_logging.h",
+    "mac/memory_pressure_monitor_mac.cc",
+    "mac/memory_pressure_monitor_mac.h",
     "mac/objc_property_releaser.h",
     "mac/objc_property_releaser.mm",
     "mac/os_crash_dumps.cc",
@@ -1067,6 +1072,7 @@
     "android/jni_android_unittest.cc",
     "android/jni_array_unittest.cc",
     "android/jni_string_unittest.cc",
+    "android/library_loader/library_prefetcher_unittest.cc",
     "android/path_utils_unittest.cc",
     "android/scoped_java_ref_unittest.cc",
     "android/sys_utils_unittest.cc",
@@ -1092,6 +1098,7 @@
     "containers/hash_tables_unittest.cc",
     "containers/linked_list_unittest.cc",
     "containers/mru_cache_unittest.cc",
+    "containers/scoped_ptr_hash_map_unittest.cc",
     "containers/small_map_unittest.cc",
     "containers/stack_container_unittest.cc",
     "cpu_unittest.cc",
@@ -1448,6 +1455,7 @@
   android_library("base_java_test_support") {
     deps = [
       ":base_java",
+      "//testing/android/reporter:reporter_java",
     ]
     DEPRECATED_java_in_dir = "test/android/javatests/src"
   }
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
index 1049628..ce78bf9 100644
--- a/base/android/application_status_listener_unittest.cc
+++ b/base/android/application_status_listener_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/callback_forward.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
@@ -49,9 +49,8 @@
   void Run() {
     // Start the thread and tell it to register for events.
     thread_.Start();
-    thread_.message_loop()
-        ->PostTask(FROM_HERE,
-                   base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
+    thread_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
                               base::Unretained(this)));
 
     // Wait for its completion.
diff --git a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
index d4b0d98..ad5cdd8 100644
--- a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
+++ b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
@@ -9,8 +9,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.TimeAnimator;
 import android.animation.TimeAnimator.TimeListener;
-import android.annotation.TargetApi;
-import android.os.Build;
 import android.util.Log;
 
 /**
@@ -82,9 +80,6 @@
     /**
      * Record Android animation frame rate and return the result.
      */
-    // Note: TimeAnimator was added to the Android public API in level 16, but has actually been
-    // available since level 14. So, it's safe to use TimeAnimator here, even on ICS.
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
     private static class Recorder implements TimeListener {
         // TODO(kkimlabs): If we can use in the future, migrate to Choreographer for minimal
         //                 workload.
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 40cb035..3df7b92 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -375,4 +375,16 @@
             return res.getDrawable(id);
         }
     }
+
+    /**
+     * @see android.content.res.Resources#getDrawableForDensity(int id, int density).
+     */
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawableForDensity(Resources res, int id, int density) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return res.getDrawableForDensity(id, density, null);
+        } else {
+            return res.getDrawableForDensity(id, density);
+        }
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
index 99d755d..4c79a4d 100644
--- a/base/android/java/src/org/chromium/base/Log.java
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -24,22 +24,23 @@
  * calls will be stripped out of the binary. Concatenations and method calls however will still
  * remain and be executed. If they can't be avoided, try to generate the logs in a method annotated
  * with {@link NoSideEffects}. Another possibility is to use
- * {@link android.util.Log#isLoggable(String, int)}, with {@link Log#makeTag(String)} to get the
- * correct tag.
+ * {@link android.util.Log#isLoggable(String, int)} to guard those calls.
  * </p>
  *
  * Usage:
  * <pre>
+ * private static final String TAG = Log.makeTag("Group");
+ *
  * private void myMethod(String awesome) {
- *   Log.i("Group", "My %s message.", awesome);
- *   Log.d("Group", "My debug message");
+ *   Log.i(TAG, "My %s message.", awesome);
+ *   Log.d(TAG, "My debug message");
  * }
  * </pre>
  *
  * Logcat output:
  * <pre>
- * I/chromium.Group (999): My awesome message
- * D/chromium.Group (999): [MyClass.java:42] My debug message
+ * I/cr.Group (999): My awesome message
+ * D/cr.Group (999): [MyClass.java:42] My debug message
  * </pre>
  *
  * Set the log level for a given group:
@@ -48,7 +49,25 @@
  * </pre>
  */
 public class Log {
-    private static final String BASE_TAG = "chromium";
+    private static final String BASE_TAG = "cr";
+
+    /** Convenience property, same as {@link android.util.Log#ASSERT}. */
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    /** Convenience property, same as {@link android.util.Log#DEBUG}. */
+    public static final int DEBUG = android.util.Log.DEBUG;
+
+    /** Convenience property, same as {@link android.util.Log#ERROR}. */
+    public static final int ERROR = android.util.Log.ERROR;
+
+    /** Convenience property, same as {@link android.util.Log#INFO}. */
+    public static final int INFO = android.util.Log.INFO;
+
+    /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+
+    /** Convenience property, same as {@link android.util.Log#WARN}. */
+    public static final int WARN = android.util.Log.WARN;
 
     private Log() {
         // Static only access
@@ -73,13 +92,26 @@
 
     /**
      * Returns a full tag for the provided group tag. Full tags longer than 23 characters
-     * will cause a runtime exception later. (see {@link android.util.Log#isLoggable(String, int)})
+     * 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.
      */
     public static String makeTag(String groupTag) {
         if (TextUtils.isEmpty(groupTag)) return BASE_TAG;
-        return BASE_TAG + "." + groupTag;
+        String tag = BASE_TAG + "." + 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);
     }
 
     /**
@@ -89,16 +121,15 @@
      * than 7 parameters, consider building your log message using a function annotated with
      * {@link NoSideEffects}.
      *
-     * @param groupTag Used to identify the source of a log message. It usually refers to the
-     *                 package or feature, to logically group related logs.
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
      *
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @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.
      */
-    private static void verbose(String groupTag, String messageTemplate, Object... args) {
-        String tag = makeTag(groupTag);
+    private static void verbose(String tag, String messageTemplate, Object... args) {
         if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
             String message = formatLogWithStack(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
@@ -111,48 +142,48 @@
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
-    public static void v(String groupTag, String message) {
-        verbose(groupTag, message);
+    public static void v(String tag, String message) {
+        verbose(tag, message);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
-    public static void v(String groupTag, String messageTemplate, Object arg1) {
-        verbose(groupTag, messageTemplate, arg1);
+    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 */
-    public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2) {
-        verbose(groupTag, messageTemplate, arg1, arg2);
+    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 */
     public static void v(
-            String groupTag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
-        verbose(groupTag, messageTemplate, arg1, arg2, arg3);
+            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 */
-    public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4) {
-        verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4);
+    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 */
-    public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4, Object arg5) {
-        verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+    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 */
-    public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4, Object arg5, Object arg6) {
-        verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+    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 */
-    public static void v(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
-        verbose(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    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);
     }
 
     /**
@@ -162,16 +193,15 @@
      * than 7 parameters, consider building your log message using a function annotated with
      * {@link NoSideEffects}.
      *
-     * @param groupTag Used to identify the source of a log message. It usually refers to the
-     *                 package or feature, to logically group related logs.
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
      *
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @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.
      */
-    private static void debug(String groupTag, String messageTemplate, Object... args) {
-        String tag = makeTag(groupTag);
+    private static void debug(String tag, String messageTemplate, Object... args) {
         if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
             String message = formatLogWithStack(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
@@ -184,60 +214,59 @@
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
-    public static void d(String groupTag, String message) {
-        debug(groupTag, message);
+    public static void d(String tag, String message) {
+        debug(tag, message);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
-    public static void d(String groupTag, String messageTemplate, Object arg1) {
-        debug(groupTag, messageTemplate, arg1);
+    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 */
-    public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2) {
-        debug(groupTag, messageTemplate, arg1, arg2);
+    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 */
     public static void d(
-            String groupTag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
-        debug(groupTag, messageTemplate, arg1, arg2, arg3);
+            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 */
-    public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4) {
-        debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4);
+    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 */
-    public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4, Object arg5) {
-        debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+    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 */
-    public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4, Object arg5, Object arg6) {
-        debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+    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 */
-    public static void d(String groupTag, String messageTemplate, Object arg1, Object arg2,
-            Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
-        debug(groupTag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    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);
     }
 
     /**
      * Sends an {@link android.util.Log#INFO} log message.
      *
-     * @param groupTag Used to identify the source of a log message. It usually refers to the
-     *                 package or feature, to logically group related logs.
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @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.
      */
-    public static void i(String groupTag, String messageTemplate, Object... args) {
-        String tag = makeTag(groupTag);
+    public static void i(String tag, String messageTemplate, Object... args) {
         if (android.util.Log.isLoggable(tag, android.util.Log.INFO)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
@@ -252,15 +281,14 @@
     /**
      * Sends a {@link android.util.Log#WARN} log message.
      *
-     * @param groupTag Used to identify the source of a log message. It usually refers to the
-     *                 package or feature, to logically group related logs.
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @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.
      */
-    public static void w(String groupTag, String messageTemplate, Object... args) {
-        String tag = makeTag(groupTag);
+    public static void w(String tag, String messageTemplate, Object... args) {
         if (android.util.Log.isLoggable(tag, android.util.Log.WARN)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
@@ -275,15 +303,14 @@
     /**
      * Sends an {@link android.util.Log#ERROR} log message.
      *
-     * @param groupTag Used to identify the source of a log message. It usually refers to the
-     *                 package or feature, to logically group related logs.
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @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.
      */
-    public static void e(String groupTag, String messageTemplate, Object... args) {
-        String tag = makeTag(groupTag);
+    public static void e(String tag, String messageTemplate, Object... args) {
         if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
@@ -302,15 +329,14 @@
      *
      * @see android.util.Log#wtf(String, String, Throwable)
      *
-     * @param groupTag Used to identify the source of a log message. It usually refers to the
-     *                 package or feature, to logically group related logs.
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @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.
      */
-    public static void wtf(String groupTag, String messageTemplate, Object... args) {
-        String tag = makeTag(groupTag);
+    public static void wtf(String tag, String messageTemplate, Object... args) {
         if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
diff --git a/base/android/java/src/org/chromium/base/OWNERS b/base/android/java/src/org/chromium/base/OWNERS
new file mode 100644
index 0000000..d99aec1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/OWNERS
@@ -0,0 +1,2 @@
+per-file ApiCompatibilityUtils.java=aurimas@chromium.org
+per-file ApiCompatibilityUtils.java=newt@chromium.org
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index 5da080e..0b3ed20 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -41,7 +41,10 @@
                 paths[DATA_DIRECTORY] =
                         appContext.getDir(dataDirectorySuffix[0], Context.MODE_PRIVATE).getPath();
                 paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
-                paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
+                // TODO(wnwen): Find a way to avoid calling this function in renderer process.
+                if (appContext.getCacheDir() != null) {
+                    paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
+                }
                 return paths;
             }
         }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, suffix);
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
new file mode 100644
index 0000000..2193826
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/README_logging.md
@@ -0,0 +1,159 @@
+## Logging ##
+
+Logging used to be done using Android's [android.util.Log]
+(http://developer.android.com/reference/android/util/Log.html).
+
+A wrapper on that is now available: org.chromium.base.Log. It is designed to write logs as
+belonging to logical groups going beyond single classes, and to make it easy to switch logging on
+or off for individual groups.
+
+Usage:
+
+    private static final String TAG = Log.makeTag("Tag");
+    ...
+    Log.i(TAG, "Some debug info: %s", data);
+
+Output:
+
+    D/cr.Tag: ( 999): [MyClass.java:42] Some debug info: data's toString output"
+
+Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for example. In most
+cases, the class name is not needed anymore. In Debug and Verbose logs, the file name and line
+number will be prepended to the log message. For higher priority logs, those are currently not
+added for performance concerns. It might be useful to make the log messages meaningful enough so
+that with the group tag, it's easy to pinpoint their origin.
+
+All log calls are guarded, which allows to enable or disable logging specific groups using ADB:
+
+    adb shell setprop log.tag.<YOUR_LOG_TAG> <LEVEL>
+
+Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`, and the
+log tag looks like `cr.Tag`. By default, the level for all tags is `INFO`.
+
+**Caveat:** Property keys are limited to 23 characters. If the tag is too long, `Log#isLoggable`
+throws a RuntimeException.
+
+### Logging Best Practices
+
+#### Rule #1: Never log PII (Personal Identification Information):
+
+This is a huge concern, because other applications can access the log and extract a lot of data
+from your own by doing so. Even if JellyBean restricted this, people are going to run your
+application on rooted devices and allow some apps to access it. Also anyone with USB access to the
+device can use ADB to get the full logcat and get the same data right now.
+
+If you really need to print something , print a series of Xs instead (e.g. "XXXXXX"), or print a
+truncated hash of the PII instead. Truncation is required to make it harder for an attacker to
+recover the full data through rainbow tables and similar methods.
+
+Similarly, avoid dumping API keys, cookies, etc...
+
+#### Rule #2: Do not write debug logs in production code:
+
+The kernel log buffer is global and of limited size. Any extra debug log you add to your activity
+or service makes it more difficult to diagnose problems on other parts of the system, because they
+tend to push the interesting bit out of the buffer too soon. This is a recurring problem on
+Android, so avoid participating into it.
+
+All verbose and debug log calls made using `org.chromium.base.Log` will be stripped out of
+production binaries using Proguard. So there will be no way to get those logs in a release build.
+For other levels, they can be disabled using system properties. Because log messages might not be
+written, the cost of creating them should also be avoided. This can be done using three
+complementary ways:
+
+-   Use string formatting instead of concatenations
+
+        // BAD
+        Log.d(TAG, "I " + preference + " writing logs.");
+
+        // BETTER
+        Log.d(TAG, "I %s writing logs.", preference);
+
+    If logging is disabled, the function's arguments will still have to be computed and provided
+    as input. The first call above will always lead to the creation of a `StringBuilder` and a few
+    concatenations, while the second just passes the arguments and won't need that.
+
+-   Guard expensive calls
+
+    Sometimes the values to log aren't readily available and need to be computed specially. This
+    should be avoided when logging is disabled.
+
+    Using `Log#isLoggable` will return whether logging for a specific tag is allowed or not. It is
+    the call used inside the log functions and using allows to know when running the expensive
+    functions is needed.
+
+        if (Log.isLoggable(TAG, Log.DEBUG) {
+          Log.d(TAG, "Something happened: %s", dumpDom(tab));
+        }
+
+    For more info, See the [android framework documentation]
+    (http://developer.android.com/tools/debugging/debugging-log.html).
+
+    Using a debug constant is a less flexible, but more perfomance oriented alternative.
+
+        static private final boolean DEBUG = false;  // set to 'true' to enable debug
+        ...
+        if (DEBUG) {
+          Log.i(TAG, createThatExpensiveLogMessage(activity))
+        }
+
+    Because the variable is a `static final` that can be evaluated at compile time, the Java
+    compiler will optimize out all guarded calls from the generated `.class` file. Changing it
+    however requires editing each of the files for which debug should be enabled and recompiling,
+    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.
+
+    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
+    function is not called at all, it will also be removed. Since Proguard is already used to
+    strip debug and verbose calls out of release builds, this annotation allows it to have a
+    deeper action by removing also function calls used to generate the log call's arguments.
+  
+        /* If that function is only used in Log.d calls, proguard should completely remove it from
+         * the release builds. */
+        @NoSideEffects
+        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. */
+          if (!Log.isLoggable(TAG, Log.DEBUG)) return null;
+
+          StringBuilder sb = new StringBuilder("Reporting " + thing.length + " things:");
+          for (Thing thing : things) {
+            sb.append('\n').append(thing.id).append(' ').append(report.foo);
+          }
+          return sb.toString();
+        }
+
+        public void bar() {
+          ...
+          Log.d(TAG, getSomeDebugLogString(things)); /* In debug builds, the function does nothing
+                                                      * is debug is disabled, and the entire line 
+                                                      * is removed in release builds. */
+        }
+
+    Again, this is useful only if the input to that function are variables already available in
+    the scope. The idea is to move computations, concatenations, etc. to a place where that can be
+    removed when not needed, without invading the main function's logic.
+
+#### Rule #3: Favor small log messages
+
+This is still related to the global fixed-sized kernel buffer used to keep all logs. Try to make
+your log information as terse as possible. This reduces the risk of pushing interesting log data
+out of the buffer when something really nasty happens. It's really better to have a single-line
+log message, than several ones. I.e. don't use:
+
+    Log.GROUP.d(TAG, "field1 = %s", value1);
+    Log.GROUP.d(TAG, "field2 = %s", value2);
+    Log.GROUP.d(TAG, "field3 = %s", value3);
+
+Instead, write this as:
+
+    Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
+
+That doesn't seem to be much different if you count overall character counts, but each independent
+log entry also implies a small, but non-trivial header, in the kernel log buffer.
+And since every byte count, you can also try something even shorter, as in:
+
+    Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index 2a8deeb..c0b9172 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -176,6 +176,7 @@
      * @param task The Runnable to run
      * @param delayMillis The delay in milliseconds until the Runnable will be run
      */
+    @VisibleForTesting
     public static void postOnUiThreadDelayed(Runnable task, long delayMillis) {
         getUiThreadHandler().postDelayed(task, delayMillis);
     }
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 7dc015d..9dc6865 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
@@ -5,7 +5,6 @@
 package org.chromium.base.library_loader;
 
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.os.AsyncTask;
 import android.os.SystemClock;
 import android.util.Log;
@@ -15,14 +14,8 @@
 import org.chromium.base.JNINamespace;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.HashMap;
 import java.util.Locale;
 
 import javax.annotation.Nullable;
@@ -97,9 +90,6 @@
     // final (like now) or be protected in some way (volatile of synchronized).
     private final int mLibraryProcessType;
 
-    // Library -> Path it has been loaded from.
-    private final HashMap<String, String> mLoadedFrom;
-
     /**
      * @param libraryProcessType the process the shared library is loaded in. refer to
      *                           LibraryProcessType for possible values.
@@ -119,7 +109,6 @@
 
     private LibraryLoader(int libraryProcessType) {
         mLibraryProcessType = libraryProcessType;
-        mLoadedFrom = new HashMap<String, String>();
     }
 
     /**
@@ -204,43 +193,10 @@
         }
     }
 
-    private void prefetchLibraryToMemory(Context context, String library) {
-        String libFilePath = mLoadedFrom.get(library);
-        if (libFilePath == null) {
-            Log.i(TAG, "File path not found for " + library);
-            return;
-        }
-        String apkFilePath = context.getApplicationInfo().sourceDir;
-        if (libFilePath.equals(apkFilePath)) {
-            // TODO(lizeb): Make pre-faulting work with libraries loaded from the APK.
-            return;
-        }
-        try {
-            TraceEvent.begin("LibraryLoader.prefetchLibraryToMemory");
-            File file = new File(libFilePath);
-            int size = (int) file.length();
-            FileChannel channel = new RandomAccessFile(file, "r").getChannel();
-            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
-            // TODO(lizeb): Figure out whether walking the entire library is really necessary.
-            // Page size is 4096 for all current Android architectures.
-            for (int index = 0; index < size; index += 4096) {
-                // Note: Testing shows that neither the Java compiler nor
-                // Dalvik/ART eliminates this loop.
-                buffer.get(index);
-            }
-        } catch (FileNotFoundException e) {
-            Log.w(TAG, "Library file not found: " + e);
-        } catch (IOException e) {
-            Log.w(TAG, "Impossible to map the file: " + e);
-        } finally {
-            TraceEvent.end("LibraryLoader.prefetchLibraryToMemory");
-        }
-    }
-
     /** Prefetches the native libraries in a background thread.
      *
-     * Launches an AsyncTask that maps the native libraries into memory, reads a
-     * part of each page from it, than unmaps it. This is done to warm up the
+     * Launches an AsyncTask that, through a short-lived forked process, reads a
+     * part of each page of the native library.  This is done to warm up the
      * page cache, turning hard page faults into soft ones.
      *
      * This is done this way, as testing shows that fadvise(FADV_WILLNEED) is
@@ -252,15 +208,13 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                // Note: AsyncTasks are executed in a low priority background
-                // thread, which is the desired behavior here since we don't
-                // want to interfere with the rest of the initialization.
-                for (String library : NativeLibraries.LIBRARIES) {
-                    if (Linker.isChromiumLinkerLibrary(library)) {
-                        continue;
-                    }
-                    prefetchLibraryToMemory(context, library);
+                TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory");
+                boolean success = nativeForkAndPrefetchNativeLibrary();
+                if (!success) {
+                    Log.w(TAG, "Forking a process to prefetch the native library failed.");
                 }
+                RecordHistogram.recordBooleanHistogram("LibraryLoader.PrefetchStatus", success);
+                TraceEvent.end("LibraryLoader.asyncPrefetchLibrariesToMemory");
                 return null;
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -340,7 +294,6 @@
                                                 ? "using no map executable support fallback"
                                                 : "directly")
                                         + " from within " + apkFilePath);
-                                mLoadedFrom.put(library, apkFilePath);
                             } else {
                                 // Unpack library fallback.
                                 Log.i(TAG, "Loading " + library
@@ -350,19 +303,10 @@
                                         context, library);
                                 fallbackWasUsed = true;
                                 Log.i(TAG, "Built fallback library " + libFilePath);
-                                mLoadedFrom.put(library, libFilePath);
                             }
                         } else {
                             // The library is in its own file.
                             Log.i(TAG, "Loading " + library);
-                            if (context != null) {
-                                ApplicationInfo applicationInfo = context.getApplicationInfo();
-                                File file = new File(applicationInfo.nativeLibraryDir, libFilePath);
-                                mLoadedFrom.put(library, file.getAbsolutePath());
-                            } else {
-                                Log.i(TAG, "No context, cannot locate the native library file for "
-                                        + library);
-                            }
                         }
 
                         // Load the library.
@@ -580,4 +524,9 @@
     // 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.
     private native String nativeGetVersionNumber();
+
+    // Finds the ranges corresponding to the native library pages, forks a new
+    // process to prefetch these pages and waits for it. The new process then
+    // terminates. This is blocking.
+    private static native boolean nativeForkAndPrefetchNativeLibrary();
 }
diff --git a/base/android/java/templates/NativeLibraries.template b/base/android/java/templates/NativeLibraries.template
index d9f6a55..8b812a6 100644
--- a/base/android/java/templates/NativeLibraries.template
+++ b/base/android/java/templates/NativeLibraries.template
@@ -74,7 +74,7 @@
     // array defined, and then the build system creates a version of the file
     // with the real list of libraries required (which changes based upon which
     // .apk is being built).
-    // TODO(cjhopman): This is public since it is referenced by ChromeNativeTestActivity.java
+    // TODO(cjhopman): This is public since it is referenced by NativeTestActivity.java
     // directly. The two ways of library loading should be refactored into one.
     public static final String[] LIBRARIES =
 #if defined(NATIVE_LIBRARIES_LIST)
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index a157354..1bbc669 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -53,7 +53,7 @@
 
 ScopedJavaLocalRef<jintArray> ToJavaIntArray(
     JNIEnv* env, const std::vector<int>& ints) {
-  return ToJavaIntArray(env, ints.begin(), ints.size());
+  return ToJavaIntArray(env, ints.data(), ints.size());
 }
 
 ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
@@ -72,7 +72,7 @@
 // Returns a new Java long array converted from the given int64 array.
 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
     JNIEnv* env, const std::vector<int64>& longs) {
-  return ToJavaLongArray(env, longs.begin(), longs.size());
+  return ToJavaLongArray(env, longs.data(), longs.size());
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
index 14726fe..46bdc67 100644
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -25,9 +25,15 @@
     /** Test method for {@link Log#makeTag(String)} */
     @Test
     public void testMakeTag() {
-        assertEquals("chromium.Foo", Log.makeTag("Foo"));
-        assertEquals("chromium", Log.makeTag(null));
-        assertEquals("chromium", Log.makeTag(""));
+        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. */
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 555420a..0b59a30 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -7,6 +7,7 @@
 #include "base/android/command_line_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/library_loader/library_load_from_apk_status_codes.h"
+#include "base/android/library_loader/library_prefetcher.h"
 #include "base/at_exit.h"
 #include "base/metrics/histogram.h"
 #include "jni/LibraryLoader_jni.h"
@@ -122,6 +123,10 @@
   }
 }
 
+static jboolean ForkAndPrefetchNativeLibrary(JNIEnv* env, jclass clazz) {
+  return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+}
+
 bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
new file mode 100644
index 0000000..798a283
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -0,0 +1,150 @@
+// 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/android/library_loader/library_prefetcher.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+// Android defines the background priority to this value since at least 2009
+// (see Process.java).
+const int kBackgroundPriority = 10;
+// Valid for all the Android architectures.
+const size_t kPageSize = 4096;
+const char* kLibchromeSuffix = "libchrome.so";
+// "base.apk" is a suffix because the library may be loaded directly from the
+// APK.
+const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
+
+bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
+  return region.permissions & base::debug::MappedMemoryRegion::READ &&
+         region.permissions & base::debug::MappedMemoryRegion::PRIVATE;
+}
+
+bool PathMatchesSuffix(const std::string& path) {
+  for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
+    if (EndsWith(path, kSuffixesToMatch[i], true)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// For each range, reads a byte per page to force it into the page cache.
+// Heap allocations, syscalls and library functions are not allowed in this
+// function.
+// Returns true for success.
+bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
+  for (const auto& range : ranges) {
+    const uintptr_t page_mask = kPageSize - 1;
+    // If start or end is not page-aligned, parsing went wrong. It is better to
+    // exit with an error.
+    if ((range.first & page_mask) || (range.second & page_mask)) {
+      return false;  // CHECK() is not allowed here.
+    }
+    unsigned char* start_ptr = reinterpret_cast<unsigned char*>(range.first);
+    unsigned char* end_ptr = reinterpret_cast<unsigned char*>(range.second);
+    unsigned char dummy = 0;
+    for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
+      // Volatile is required to prevent the compiler from eliminating this
+      // loop.
+      dummy ^= *static_cast<volatile unsigned char*>(ptr);
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+// static
+bool NativeLibraryPrefetcher::IsGoodToPrefetch(
+    const base::debug::MappedMemoryRegion& region) {
+  return PathMatchesSuffix(region.path) &&
+         IsReadableAndPrivate(region);  // .text and .data mappings are private.
+}
+
+// static
+void NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(
+    const std::vector<base::debug::MappedMemoryRegion>& regions,
+    std::vector<AddressRange>* ranges) {
+  bool has_libchrome_region = false;
+  for (const base::debug::MappedMemoryRegion& region : regions) {
+    if (EndsWith(region.path, kLibchromeSuffix, true)) {
+      has_libchrome_region = true;
+      break;
+    }
+  }
+  for (const base::debug::MappedMemoryRegion& region : regions) {
+    if (has_libchrome_region &&
+        !EndsWith(region.path, kLibchromeSuffix, true)) {
+      continue;
+    }
+    ranges->push_back(std::make_pair(region.start, region.end));
+  }
+}
+
+// static
+bool NativeLibraryPrefetcher::FindRanges(std::vector<AddressRange>* ranges) {
+  std::string proc_maps;
+  if (!base::debug::ReadProcMaps(&proc_maps))
+    return false;
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  if (!base::debug::ParseProcMaps(proc_maps, &regions))
+    return false;
+
+  std::vector<base::debug::MappedMemoryRegion> regions_to_prefetch;
+  for (const auto& region : regions) {
+    if (IsGoodToPrefetch(region)) {
+      regions_to_prefetch.push_back(region);
+    }
+  }
+
+  FilterLibchromeRangesOnlyIfPossible(regions_to_prefetch, ranges);
+  return true;
+}
+
+// static
+bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+  // Looking for ranges is done before the fork, to avoid syscalls and/or memory
+  // allocations in the forked process. The child process inherits the lock
+  // state of its parent thread. It cannot rely on being able to acquire any
+  // lock (unless special care is taken in a pre-fork handler), including being
+  // able to call malloc().
+  std::vector<AddressRange> ranges;
+  if (!FindRanges(&ranges))
+    return false;
+  pid_t pid = fork();
+  if (pid == 0) {
+    setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
+    // _exit() doesn't call the atexit() handlers.
+    _exit(Prefetch(ranges) ? 0 : 1);
+  } else {
+    if (pid < 0) {
+      return false;
+    }
+    int status;
+    const pid_t result = HANDLE_EINTR(waitpid(pid, &status, 0));
+    if (result == pid) {
+      if (WIFEXITED(status)) {
+        return WEXITSTATUS(status) == 0;
+      }
+    }
+    return false;
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
new file mode 100644
index 0000000..64e5e1e
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.h
@@ -0,0 +1,67 @@
+// 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_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+
+#include <jni.h>
+
+#include <stdint.h>
+#include <string>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace android {
+
+// Forks and waits for a process prefetching the native library. This is done in
+// a forked process for the following reasons:
+// - Isolating the main process from mistakes in the parsing. If the parsing
+//   returns an incorrect address, only the forked process will crash.
+// - Not inflating the memory used by the main process uselessly, which could
+//   increase its likelihood to be killed.
+// The forked process has background priority and, since it is not declared to
+// the Android runtime, can be killed at any time, which is not an issue here.
+class BASE_EXPORT NativeLibraryPrefetcher {
+ public:
+  // Finds the ranges matching the native library, forks a low priority
+  // process pre-fetching these ranges and wait()s for it.
+  // Returns true for success.
+  static bool ForkAndPrefetchNativeLibrary();
+
+ private:
+  using AddressRange = std::pair<uintptr_t, uintptr_t>;
+  // Returns true if the region matches native code or data.
+  static bool IsGoodToPrefetch(const base::debug::MappedMemoryRegion& region);
+  // Filters the regions to keep only libchrome ranges if possible.
+  static void FilterLibchromeRangesOnlyIfPossible(
+      const std::vector<base::debug::MappedMemoryRegion>& regions,
+      std::vector<AddressRange>* ranges);
+  // Finds the ranges matching the native library in /proc/self/maps.
+  // Returns true for success.
+  static bool FindRanges(std::vector<AddressRange>* ranges);
+
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchNoRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchUnreadableRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchSkipSharedRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchLibchromeRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchBaseApkRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
diff --git a/base/android/library_loader/library_prefetcher_unittest.cc b/base/android/library_loader/library_prefetcher_unittest.cc
new file mode 100644
index 0000000..7b7296f
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher_unittest.cc
@@ -0,0 +1,95 @@
+// 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/android/library_loader/library_prefetcher.h"
+
+#include <string>
+#include <vector>
+#include "base/debug/proc_maps_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+const uint8 kRead = base::debug::MappedMemoryRegion::READ;
+const uint8 kReadPrivate = base::debug::MappedMemoryRegion::READ |
+                           base::debug::MappedMemoryRegion::PRIVATE;
+const uint8 kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
+                              base::debug::MappedMemoryRegion::PRIVATE;
+}  // namespace
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
+  const base::debug::MappedMemoryRegion regions[4] = {
+      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, ""},
+      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, "foo"},
+      base::debug::MappedMemoryRegion{
+          0x4000, 0x5000, 10, kReadPrivate, "foobar.apk"},
+      base::debug::MappedMemoryRegion{
+          0x4000, 0x5000, 10, kReadPrivate, "libchromium.so"}};
+  for (int i = 0; i < 4; ++i) {
+    ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(regions[i]));
+  }
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchUnreadableRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kExecutePrivate, "base.apk"};
+  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchSkipSharedRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kRead, "base.apk"};
+  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchLibchromeRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kReadPrivate, "libchrome.so"};
+  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchBaseApkRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kReadPrivate, "base.apk"};
+  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest,
+     TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome) {
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+                                                               &ranges);
+  EXPECT_EQ(ranges.size(), 2U);
+  EXPECT_EQ(ranges[0].first, 0x1U);
+  EXPECT_EQ(ranges[0].second, 0x2U);
+  EXPECT_EQ(ranges[1].first, 0x3U);
+  EXPECT_EQ(ranges[1].second, 0x4U);
+}
+
+TEST(NativeLibraryPrefetcherTest,
+     TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome) {
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+  regions.push_back(base::debug::MappedMemoryRegion{
+      0x6, 0x7, 0, kReadPrivate, "libchrome.so"});
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+                                                               &ranges);
+  EXPECT_EQ(ranges.size(), 1U);
+  EXPECT_EQ(ranges[0].first, 0x6U);
+  EXPECT_EQ(ranges[0].second, 0x7U);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/async_socket_io_handler_unittest.cc b/base/async_socket_io_handler_unittest.cc
index 2b0e3c2..721de9c 100644
--- a/base/async_socket_io_handler_unittest.cc
+++ b/base/async_socket_io_handler_unittest.cc
@@ -5,6 +5,9 @@
 #include "base/async_socket_io_handler.h"
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -104,8 +107,8 @@
   TestSocketReader reader(&pair[0], -1, false, false);
 
   pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       base::TimeDelta::FromMilliseconds(100));
   base::MessageLoop::current()->Run();
 
@@ -135,15 +138,15 @@
   // Issue sends on an interval to satisfy the Read() requirements.
   int64 milliseconds = 0;
   for (int i = 0; i < kReadOperationCount; ++i) {
-    base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-        base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
-            kAsyncSocketIoTestStringLength),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
+                              kAsyncSocketIoTestStringLength),
         base::TimeDelta::FromMilliseconds(milliseconds));
     milliseconds += 10;
   }
 
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       base::TimeDelta::FromMilliseconds(100 + milliseconds));
 
   base::MessageLoop::current()->Run();
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
index 553fab6..2ab7242 100644
--- a/base/atomic_ref_count.h
+++ b/base/atomic_ref_count.h
@@ -4,9 +4,6 @@
 
 // This is a low level implementation of atomic semantics for reference
 // counting.  Please use base/memory/ref_counted.h directly instead.
-//
-// The implementation includes annotations to avoid some false positives
-// when using data race detection tools.
 
 #ifndef BASE_ATOMIC_REF_COUNT_H_
 #define BASE_ATOMIC_REF_COUNT_H_
diff --git a/base/base.gyp b/base/base.gyp
index e9d3e81..80c3f10 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -438,6 +438,7 @@
         'android/jni_android_unittest.cc',
         'android/jni_array_unittest.cc',
         'android/jni_string_unittest.cc',
+        'android/library_loader/library_prefetcher_unittest.cc',
         'android/path_utils_unittest.cc',
         'android/scoped_java_ref_unittest.cc',
         'android/sys_utils_unittest.cc',
@@ -463,6 +464,7 @@
         'containers/hash_tables_unittest.cc',
         'containers/linked_list_unittest.cc',
         'containers/mru_cache_unittest.cc',
+        'containers/scoped_ptr_hash_map_unittest.cc',
         'containers/small_map_unittest.cc',
         'containers/stack_container_unittest.cc',
         'cpu_unittest.cc',
@@ -515,6 +517,7 @@
         'mac/foundation_util_unittest.mm',
         'mac/libdispatch_task_runner_unittest.cc',
         'mac/mac_util_unittest.mm',
+        'mac/memory_pressure_monitor_mac_unittest.cc',
         'mac/objc_property_releaser_unittest.mm',
         'mac/scoped_nsobject_unittest.mm',
         'mac/scoped_objc_class_swizzler_unittest.mm',
@@ -1476,6 +1479,7 @@
           'type': 'none',
           'dependencies': [
             'base_java',
+            '../testing/android/on_device_instrumentation.gyp:reporter_java',
           ],
           'variables': {
             'java_in_dir': '../base/test/android/javatests',
diff --git a/base/base.gypi b/base/base.gypi
index bbc3f60..4a8cd17 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -62,6 +62,8 @@
           'android/library_loader/library_load_from_apk_status_codes.h',
           'android/library_loader/library_loader_hooks.cc',
           'android/library_loader/library_loader_hooks.h',
+          'android/library_loader/library_prefetcher.cc',
+          'android/library_loader/library_prefetcher.h',
           'android/locale_utils.cc',
           'android/locale_utils.h',
           'android/memory_pressure_listener_android.cc',
@@ -290,6 +292,8 @@
           'mac/mac_util.mm',
           'mac/mach_logging.cc',
           'mac/mach_logging.h',
+          'mac/memory_pressure_monitor_mac.cc',
+          'mac/memory_pressure_monitor_mac.h',
           'mac/objc_property_releaser.h',
           'mac/objc_property_releaser.mm',
           'mac/os_crash_dumps.cc',
@@ -866,6 +870,7 @@
               ['include', '^mac/scoped_mach_vm\\.'],
               ['include', '^mac/scoped_nsautorelease_pool\\.'],
               ['include', '^mac/scoped_nsobject\\.'],
+              ['include', '^mac/scoped_objc_class_swizzler\\.'],
               ['include', '^message_loop/message_pump_mac\\.'],
               ['include', '^strings/sys_string_conversions_mac\\.'],
               ['include', '^threading/platform_thread_mac\\.'],
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
index c49b5b8..24063ad 100644
--- a/base/bind_helpers.h
+++ b/base/bind_helpers.h
@@ -129,7 +129,7 @@
 // Passed() is particularly useful with PostTask() when you are transferring
 // ownership of an argument into a task, but don't necessarily know if the
 // task will always be executed. This can happen if the task is cancellable
-// or if it is posted to a MessageLoopProxy.
+// or if it is posted to a TaskRunner.
 //
 //
 // SIMPLE FUNCTIONS AND UTILITIES.
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
index fcbe23c..6d0a114 100644
--- a/base/cancelable_callback_unittest.cc
+++ b/base/cancelable_callback_unittest.cc
@@ -6,9 +6,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -165,12 +167,12 @@
   CancelableClosure cancelable(base::Bind(&Increment,
                                            base::Unretained(&count)));
 
-  MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
   RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1, count);
 
-  MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
 
   // Cancel before running the message loop.
   cancelable.Cancel();
diff --git a/base/chromeos/memory_pressure_monitor_chromeos.cc b/base/chromeos/memory_pressure_monitor_chromeos.cc
index 404c515..82bc6a1 100644
--- a/base/chromeos/memory_pressure_monitor_chromeos.cc
+++ b/base/chromeos/memory_pressure_monitor_chromeos.cc
@@ -7,10 +7,11 @@
 #include <fcntl.h>
 #include <sys/select.h>
 
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/process_metrics.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 
 namespace base {
@@ -120,10 +121,9 @@
 }
 
 void MemoryPressureMonitorChromeOS::ScheduleEarlyCheck() {
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure,
-           weak_ptr_factory_.GetWeakPtr()));
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure,
+                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 MemoryPressureListener::MemoryPressureLevel
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
index d13c469..5ce9161 100644
--- a/base/containers/hash_tables.h
+++ b/base/containers/hash_tables.h
@@ -45,15 +45,9 @@
 #undef __DEPRECATED
 #endif
 
-#if defined(OS_ANDROID)
-#include <hash_map>
-#include <hash_set>
-#define BASE_HASH_IMPL_NAMESPACE std
-#else
 #include <ext/hash_map>
 #include <ext/hash_set>
 #define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
-#endif
 
 #include <string>
 
@@ -84,7 +78,6 @@
   }
 };
 
-#if !defined(OS_ANDROID)
 // The GNU C++ library provides identity hash functions for many integral types,
 // but not for |long long|.  This hash function will truncate if |size_t| is
 // narrower than |long long|.  This is probably good enough for what we will
@@ -102,7 +95,6 @@
 DEFINE_TRIVIAL_HASH(unsigned long long);
 
 #undef DEFINE_TRIVIAL_HASH
-#endif  // !defined(OS_ANDROID)
 
 // Implement string hash functions so that strings of various flavors can
 // be used as keys in STL maps and sets.  The hash algorithm comes from the
diff --git a/base/containers/scoped_ptr_hash_map.h b/base/containers/scoped_ptr_hash_map.h
index dedf213..8fe550e 100644
--- a/base/containers/scoped_ptr_hash_map.h
+++ b/base/containers/scoped_ptr_hash_map.h
@@ -16,12 +16,12 @@
 
 namespace base {
 
-// This type acts like a hash_map<K, scoped_ptr<V> >, based on top of
+// This type acts like a hash_map<K, scoped_ptr<V, D> >, based on top of
 // base::hash_map. The ScopedPtrHashMap has ownership of all values in the data
 // structure.
-template <typename Key, typename Value>
+template <typename Key, typename ScopedPtr>
 class ScopedPtrHashMap {
-  typedef base::hash_map<Key, Value*> Container;
+  typedef base::hash_map<Key, typename ScopedPtr::element_type*> Container;
 
  public:
   typedef typename Container::key_type key_type;
@@ -34,15 +34,17 @@
 
   ~ScopedPtrHashMap() { clear(); }
 
-  void swap(ScopedPtrHashMap<Key, Value>& other) {
+  void swap(ScopedPtrHashMap<Key, ScopedPtr>& other) {
     data_.swap(other.data_);
   }
 
   // Replaces value but not key if key is already present.
-  iterator set(const Key& key, scoped_ptr<Value> data) {
+  iterator set(const Key& key, ScopedPtr data) {
     iterator it = find(key);
     if (it != end()) {
-      delete it->second;
+      // Let ScopedPtr decide how to delete. For example, it may use custom
+      // deleter.
+      ScopedPtr(it->second).reset();
       it->second = data.release();
       return it;
     }
@@ -51,7 +53,7 @@
   }
 
   // Does nothing if key is already present
-  std::pair<iterator, bool> add(const Key& key, scoped_ptr<Value> data) {
+  std::pair<iterator, bool> add(const Key& key, ScopedPtr data) {
     std::pair<iterator, bool> result =
         data_.insert(std::make_pair(key, data.get()));
     if (result.second)
@@ -60,7 +62,8 @@
   }
 
   void erase(iterator it) {
-    delete it->second;
+    // Let ScopedPtr decide how to delete.
+    ScopedPtr(it->second).reset();
     data_.erase(it);
   }
 
@@ -72,45 +75,45 @@
     return 1;
   }
 
-  scoped_ptr<Value> take(iterator it) {
+  ScopedPtr take(iterator it) {
     DCHECK(it != data_.end());
     if (it == data_.end())
-      return scoped_ptr<Value>();
+      return ScopedPtr();
 
-    scoped_ptr<Value> ret(it->second);
+    ScopedPtr ret(it->second);
     it->second = NULL;
     return ret.Pass();
   }
 
-  scoped_ptr<Value> take(const Key& k) {
+  ScopedPtr take(const Key& k) {
     iterator it = find(k);
     if (it == data_.end())
-      return scoped_ptr<Value>();
+      return ScopedPtr();
 
     return take(it);
   }
 
-  scoped_ptr<Value> take_and_erase(iterator it) {
+  ScopedPtr take_and_erase(iterator it) {
     DCHECK(it != data_.end());
     if (it == data_.end())
-      return scoped_ptr<Value>();
+      return ScopedPtr();
 
-    scoped_ptr<Value> ret(it->second);
+    ScopedPtr ret(it->second);
     data_.erase(it);
     return ret.Pass();
   }
 
-  scoped_ptr<Value> take_and_erase(const Key& k) {
+  ScopedPtr take_and_erase(const Key& k) {
     iterator it = find(k);
     if (it == data_.end())
-      return scoped_ptr<Value>();
+      return ScopedPtr();
 
     return take_and_erase(it);
   }
 
   // Returns the element in the hash_map that matches the given key.
   // If no such element exists it returns NULL.
-  Value* get(const Key& k) const {
+  typename ScopedPtr::element_type* get(const Key& k) const {
     const_iterator it = find(k);
     if (it == end())
       return NULL;
@@ -119,7 +122,19 @@
 
   inline bool contains(const Key& k) const { return data_.count(k) > 0; }
 
-  inline void clear() { STLDeleteValues(&data_); }
+  inline void clear() {
+    auto it = data_.begin();
+    while (it != data_.end()) {
+      // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+      // Deleting the value does not always invalidate the iterator, but it may
+      // do so if the key is a pointer into the value object.
+      auto temp = it;
+      ++it;
+      // Let ScopedPtr decide how to delete.
+      ScopedPtr(temp->second).reset();
+    }
+    data_.clear();
+  }
 
   inline const_iterator find(const Key& k) const { return data_.find(k); }
   inline iterator find(const Key& k) { return data_.find(k); }
diff --git a/base/containers/scoped_ptr_hash_map_unittest.cc b/base/containers/scoped_ptr_hash_map_unittest.cc
new file mode 100644
index 0000000..88fe41f
--- /dev/null
+++ b/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -0,0 +1,85 @@
+// 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_hash_map.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct DeleteCounter {
+ public:
+  DeleteCounter() {}
+  ~DeleteCounter() { g_delete_count++; }
+
+  static void ResetCounter() { g_delete_count = 0; }
+  static int delete_count() { return g_delete_count; }
+
+ private:
+  static int g_delete_count;
+};
+
+int DeleteCounter::g_delete_count = 0;
+
+struct CountingDeleter {
+ public:
+  inline void operator()(DeleteCounter* ptr) const {
+    g_deleter_call_count++;
+    delete ptr;
+  }
+
+  static int count() { return g_deleter_call_count; }
+  static void ResetCounter() { g_deleter_call_count = 0; }
+
+ private:
+  static int g_deleter_call_count;
+};
+
+int CountingDeleter::g_deleter_call_count = 0;
+
+TEST(ScopedPtrHashMapTest, CustomDeleter) {
+  int key = 123;
+
+  // Test dtor.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+  }
+  EXPECT_EQ(1, DeleteCounter::delete_count());
+  EXPECT_EQ(1, CountingDeleter::count());
+
+  // Test set and erase.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.erase(map.set(
+        key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter)));
+    EXPECT_EQ(1, DeleteCounter::delete_count());
+    EXPECT_EQ(1, CountingDeleter::count());
+  }
+  EXPECT_EQ(1, DeleteCounter::delete_count());
+  EXPECT_EQ(1, CountingDeleter::count());
+
+  // Test set more than once.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    EXPECT_EQ(2, DeleteCounter::delete_count());
+    EXPECT_EQ(2, CountingDeleter::count());
+  }
+  EXPECT_EQ(3, DeleteCounter::delete_count());
+  EXPECT_EQ(3, CountingDeleter::count());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/critical_closure.h b/base/critical_closure.h
index ac07911..75e3704 100644
--- a/base/critical_closure.h
+++ b/base/critical_closure.h
@@ -52,7 +52,7 @@
 // returned.
 //
 // Example:
-//   file_message_loop_proxy_->PostTask(
+//   file_task_runner_->PostTask(
 //       FROM_HERE,
 //       MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
 //
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
index 3591fd6..19df8cb 100644
--- a/base/debug/task_annotator.cc
+++ b/base/debug/task_annotator.cc
@@ -28,7 +28,6 @@
 void TaskAnnotator::RunTask(const char* queue_function,
                             const char* run_function,
                             const PendingTask& pending_task) {
-  tracked_objects::ThreadData::PrepareForStartOfRun(pending_task.birth_tally);
   tracked_objects::TaskStopwatch stopwatch;
   stopwatch.Start();
   tracked_objects::Duration queue_duration =
diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc
index 81f2a0a..6e17ad9 100644
--- a/base/deferred_sequenced_task_runner_unittest.cc
+++ b/base/deferred_sequenced_task_runner_unittest.cc
@@ -7,9 +7,9 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/non_thread_safe.h"
 #include "base/threading/thread.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -58,11 +58,9 @@
   }
 
  protected:
-  DeferredSequencedTaskRunnerTest() :
-      loop_(),
-      runner_(
-          new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) {
-  }
+  DeferredSequencedTaskRunnerTest()
+      : loop_(),
+        runner_(new base::DeferredSequencedTaskRunner(loop_.task_runner())) {}
 
   base::MessageLoop loop_;
   scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
@@ -126,21 +124,18 @@
     thread1.Start();
     thread2.Start();
     for (int i = 0; i < 5; ++i) {
-      thread1.message_loop()->PostTask(
+      thread1.task_runner()->PostTask(
           FROM_HERE,
           base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
-                     base::Unretained(this),
-                     2 * i));
-      thread2.message_loop()->PostTask(
+                     base::Unretained(this), 2 * i));
+      thread2.task_runner()->PostTask(
           FROM_HERE,
           base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
-                     base::Unretained(this),
-                     2 * i + 1));
+                     base::Unretained(this), 2 * i + 1));
       if (i == 2) {
-        thread1.message_loop()->PostTask(
-            FROM_HERE,
-            base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
-                       base::Unretained(this)));
+        thread1.task_runner()->PostTask(
+            FROM_HERE, base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
+                                  base::Unretained(this)));
       }
     }
   }
@@ -154,8 +149,7 @@
   {
     base::Thread thread("DeferredSequencedTaskRunnerTestThread");
     thread.Start();
-    runner_ =
-        new base::DeferredSequencedTaskRunner(thread.message_loop_proxy());
+    runner_ = new base::DeferredSequencedTaskRunner(thread.task_runner());
     for (int i = 0; i < 5; ++i) {
       {
         // Use a block to ensure that no reference to |short_lived_object|
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
index a18dbbd..e677838 100644
--- a/base/file_version_info_mac.h
+++ b/base/file_version_info_mac.h
@@ -5,16 +5,13 @@
 #ifndef BASE_FILE_VERSION_INFO_MAC_H_
 #define BASE_FILE_VERSION_INFO_MAC_H_
 
+#include <CoreFoundation/CoreFoundation.h>
 #include <string>
 
 #include "base/file_version_info.h"
 #include "base/mac/scoped_nsobject.h"
 
-#ifdef __OBJC__
 @class NSBundle;
-#else
-class NSBundle;
-#endif
 
 class FileVersionInfoMac : public FileVersionInfo {
  public:
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index d26fa06..4f132af 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -12,7 +12,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 
 namespace base {
 
@@ -58,12 +58,13 @@
     // check |is_cancelled()| to avoid duplicate work.
     virtual void CancelOnMessageLoopThread() = 0;
 
-    scoped_refptr<base::MessageLoopProxy> message_loop() const {
-      return message_loop_;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+      return task_runner_;
     }
 
-    void set_message_loop(const scoped_refptr<base::MessageLoopProxy>& loop) {
-      message_loop_ = loop;
+    void set_task_runner(
+        scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+      task_runner_ = task_runner.Pass();
     }
 
     // Must be called before the PlatformDelegate is deleted.
@@ -76,7 +77,7 @@
     }
 
    private:
-    scoped_refptr<base::MessageLoopProxy> message_loop_;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
     bool cancelled_;
   };
 
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc
index ef4e6ee..da01c43 100644
--- a/base/files/file_path_watcher_fsevents.cc
+++ b/base/files/file_path_watcher_fsevents.cc
@@ -13,6 +13,7 @@
 #include "base/mac/libdispatch_task_runner.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace base {
 
@@ -92,7 +93,7 @@
   if (!recursive)
     return false;
 
-  set_message_loop(MessageLoopProxy::current());
+  set_task_runner(ThreadTaskRunnerHandle::Get());
   callback_ = callback;
 
   FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
@@ -152,7 +153,7 @@
 }
 
 FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {
-  // This method may be called on either the libdispatch or message_loop()
+  // This method may be called on either the libdispatch or task_runner()
   // thread. Checking callback_ on the libdispatch thread here is safe because
   // it is executing in a task posted by Cancel() which first reset callback_.
   // PostTask forms a sufficient memory barrier to ensure that the value is
@@ -165,7 +166,7 @@
     const std::vector<FilePath>& paths) {
   DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
   DCHECK(!resolved_target_.empty());
-  message_loop()->PostTask(
+  task_runner()->PostTask(
       FROM_HERE, Bind(&FilePathWatcherFSEvents::DispatchEvents, this, paths,
                       target_, resolved_target_));
 }
@@ -173,7 +174,7 @@
 void FilePathWatcherFSEvents::DispatchEvents(const std::vector<FilePath>& paths,
                                              const FilePath& target,
                                              const FilePath& resolved_target) {
-  DCHECK(message_loop()->RunsTasksOnCurrentThread());
+  DCHECK(task_runner()->RunsTasksOnCurrentThread());
 
   // Don't issue callbacks after Cancel() has been called.
   if (is_cancelled() || callback_.is_null()) {
@@ -190,7 +191,7 @@
 
 void FilePathWatcherFSEvents::CancelOnMessageLoopThread() {
   // For all other implementations, the "message loop thread" is the IO thread,
-  // as returned by message_loop(). This implementation, however, needs to
+  // as returned by task_runner(). This implementation, however, needs to
   // cancel pending work on the Dispatch Queue thread.
   DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
 
@@ -239,7 +240,7 @@
                                 g_task_runner.Get().GetDispatchQueue());
 
   if (!FSEventStreamStart(fsevent_stream_)) {
-    message_loop()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
   }
 }
@@ -250,14 +251,14 @@
   bool changed = resolved != resolved_target_;
   resolved_target_ = resolved;
   if (resolved_target_.empty()) {
-    message_loop()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
   }
   return changed;
 }
 
 void FilePathWatcherFSEvents::ReportError(const FilePath& target) {
-  DCHECK(message_loop()->RunsTasksOnCurrentThread());
+  DCHECK(task_runner()->RunsTasksOnCurrentThread());
   if (!callback_.is_null()) {
     callback_.Run(target, true);
   }
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
index 8941d2e..e15cba7 100644
--- a/base/files/file_path_watcher_kqueue.cc
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 
 // On some platforms these are not defined.
 #if !defined(EV_RECEIPT)
@@ -327,7 +328,7 @@
   target_ = path;
 
   MessageLoop::current()->AddDestructionObserver(this);
-  io_message_loop_ = base::MessageLoopProxy::current();
+  io_task_runner_ = ThreadTaskRunnerHandle::Get();
 
   kqueue_ = kqueue();
   if (kqueue_ == -1) {
@@ -356,14 +357,14 @@
 }
 
 void FilePathWatcherKQueue::Cancel() {
-  base::MessageLoopProxy* proxy = io_message_loop_.get();
-  if (!proxy) {
+  SingleThreadTaskRunner* task_runner = io_task_runner_.get();
+  if (!task_runner) {
     set_cancelled();
     return;
   }
-  if (!proxy->BelongsToCurrentThread()) {
-    proxy->PostTask(FROM_HERE,
-                    base::Bind(&FilePathWatcherKQueue::Cancel, this));
+  if (!task_runner->BelongsToCurrentThread()) {
+    task_runner->PostTask(FROM_HERE,
+                          base::Bind(&FilePathWatcherKQueue::Cancel, this));
     return;
   }
   CancelOnMessageLoopThread();
@@ -380,7 +381,7 @@
     kqueue_ = -1;
     std::for_each(events_.begin(), events_.end(), ReleaseEvent);
     events_.clear();
-    io_message_loop_ = NULL;
+    io_task_runner_ = NULL;
     MessageLoop::current()->RemoveDestructionObserver(this);
     callback_.Reset();
   }
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
index 87af891..69555a3 100644
--- a/base/files/file_path_watcher_kqueue.h
+++ b/base/files/file_path_watcher_kqueue.h
@@ -11,7 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 
 namespace base {
 
@@ -59,7 +59,7 @@
 
   typedef std::vector<struct kevent> EventVector;
 
-  // Can only be called on |io_message_loop_|'s thread.
+  // Can only be called on |io_task_runner_|'s thread.
   void CancelOnMessageLoopThread() override;
 
   // Returns true if the kevent values are error free.
@@ -118,7 +118,7 @@
   }
 
   EventVector events_;
-  scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
   FilePathWatcher::Callback callback_;
   FilePath target_;
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index 06c517a..ba2f1d9 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -26,10 +26,10 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/trace_event/trace_event.h"
 
@@ -264,7 +264,7 @@
   shutdown_pipe_[0] = -1;
   shutdown_pipe_[1] = -1;
   if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
-    thread_.message_loop()->PostTask(
+    thread_.task_runner()->PostTask(
         FROM_HERE,
         Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0]));
     valid_ = true;
@@ -349,12 +349,11 @@
                                             bool created,
                                             bool deleted,
                                             bool is_dir) {
-  if (!message_loop()->BelongsToCurrentThread()) {
-    // Switch to message_loop() to access |watches_| safely.
-    message_loop()->PostTask(
-        FROM_HERE,
-        Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
-             fired_watch, child, created, deleted, is_dir));
+  if (!task_runner()->BelongsToCurrentThread()) {
+    // Switch to task_runner() to access |watches_| safely.
+    task_runner()->PostTask(FROM_HERE,
+                            Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
+                                 fired_watch, child, created, deleted, is_dir));
     return;
   }
 
@@ -452,7 +451,7 @@
   DCHECK(target_.empty());
   DCHECK(MessageLoopForIO::current());
 
-  set_message_loop(MessageLoopProxy::current());
+  set_task_runner(ThreadTaskRunnerHandle::Get());
   callback_ = callback;
   target_ = path;
   recursive_ = recursive;
@@ -476,17 +475,16 @@
   }
 
   // Switch to the message_loop() if necessary so we can access |watches_|.
-  if (!message_loop()->BelongsToCurrentThread()) {
-    message_loop()->PostTask(FROM_HERE,
-                             Bind(&FilePathWatcher::CancelWatch,
-                                  make_scoped_refptr(this)));
+  if (!task_runner()->BelongsToCurrentThread()) {
+    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+                                            make_scoped_refptr(this)));
   } else {
     CancelOnMessageLoopThread();
   }
 }
 
 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
-  DCHECK(message_loop()->BelongsToCurrentThread());
+  DCHECK(task_runner()->BelongsToCurrentThread());
   set_cancelled();
 
   if (!callback_.is_null()) {
@@ -510,7 +508,7 @@
 void FilePathWatcherImpl::UpdateWatches() {
   // Ensure this runs on the message_loop() exclusively in order to avoid
   // concurrency issues.
-  DCHECK(message_loop()->BelongsToCurrentThread());
+  DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK(HasValidWatchVector());
 
   // Walk the list of watches and update them as we go.
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index 0e1c467..21e9dd1 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -20,14 +20,15 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_file_util.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,14 +47,13 @@
 class NotificationCollector
     : public base::RefCountedThreadSafe<NotificationCollector> {
  public:
-  NotificationCollector()
-      : loop_(base::MessageLoopProxy::current()) {}
+  NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
 
   // Called from the file thread by the delegates.
   void OnChange(TestDelegate* delegate) {
-    loop_->PostTask(FROM_HERE,
-                    base::Bind(&NotificationCollector::RecordChange, this,
-                               base::Unretained(delegate)));
+    task_runner_->PostTask(
+        FROM_HERE, base::Bind(&NotificationCollector::RecordChange, this,
+                              base::Unretained(delegate)));
   }
 
   void Register(TestDelegate* delegate) {
@@ -74,13 +74,13 @@
 
   void RecordChange(TestDelegate* delegate) {
     // Warning: |delegate| is Unretained. Do not dereference.
-    ASSERT_TRUE(loop_->BelongsToCurrentThread());
+    ASSERT_TRUE(task_runner_->BelongsToCurrentThread());
     ASSERT_TRUE(delegates_.count(delegate));
     signaled_.insert(delegate);
 
     // Check whether all delegates have been signaled.
     if (signaled_ == delegates_)
-      loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+      task_runner_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
   }
 
   // Set of registered delegates.
@@ -90,7 +90,7 @@
   std::set<TestDelegate*> signaled_;
 
   // The loop we should break after all delegates signaled.
-  scoped_refptr<base::MessageLoopProxy> loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
 class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
@@ -171,7 +171,7 @@
   void TearDown() override { RunLoop().RunUntilIdle(); }
 
   void DeleteDelegateOnFileThread(TestDelegate* delegate) {
-    file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, delegate);
+    file_thread_.task_runner()->DeleteSoon(FROM_HERE, delegate);
   }
 
   FilePath test_file() {
@@ -216,10 +216,9 @@
                                      bool recursive_watch) {
   base::WaitableEvent completion(false, false);
   bool result;
-  file_thread_.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(SetupWatchCallback, target, watcher, delegate, recursive_watch,
-                 &result, &completion));
+  file_thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(SetupWatchCallback, target, watcher, delegate,
+                            recursive_watch, &result, &completion));
   completion.Wait();
   return result;
 }
@@ -289,7 +288,8 @@
 
   void OnFileChanged(const FilePath&, bool) override {
     watcher_.reset();
-    loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+    loop_->task_runner()->PostTask(FROM_HERE,
+                                   MessageLoop::QuitWhenIdleClosure());
   }
 
   FilePathWatcher* watcher() const { return watcher_.get(); }
@@ -324,7 +324,7 @@
   FilePathWatcher* watcher = new FilePathWatcher;
   ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
   ASSERT_TRUE(WriteFile(test_file(), "content"));
-  file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
+  file_thread_.task_runner()->DeleteSoon(FROM_HERE, watcher);
   DeleteDelegateOnFileThread(delegate.release());
 }
 
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
index d7ce524..081698f 100644
--- a/base/files/file_path_watcher_win.cc
+++ b/base/files/file_path_watcher_win.cc
@@ -10,7 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/win/object_watcher.h"
 
@@ -57,7 +57,7 @@
   // Destroy the watch handle.
   void DestroyWatch();
 
-  // Cleans up and stops observing the |message_loop_| thread.
+  // Cleans up and stops observing the |task_runner_| thread.
   void CancelOnMessageLoopThread() override;
 
   // Callback to notify upon changes.
@@ -91,7 +91,7 @@
                                 const FilePathWatcher::Callback& callback) {
   DCHECK(target_.value().empty());  // Can only watch one path.
 
-  set_message_loop(MessageLoopProxy::current());
+  set_task_runner(ThreadTaskRunnerHandle::Get());
   callback_ = callback;
   target_ = path;
   recursive_watch_ = recursive;
@@ -113,23 +113,22 @@
 
 void FilePathWatcherImpl::Cancel() {
   if (callback_.is_null()) {
-    // Watch was never called, or the |message_loop_| has already quit.
+    // Watch was never called, or the |task_runner_| has already quit.
     set_cancelled();
     return;
   }
 
   // Switch to the file thread if necessary so we can stop |watcher_|.
-  if (!message_loop()->BelongsToCurrentThread()) {
-    message_loop()->PostTask(FROM_HERE,
-                             Bind(&FilePathWatcher::CancelWatch,
-                                  make_scoped_refptr(this)));
+  if (!task_runner()->BelongsToCurrentThread()) {
+    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+                                            make_scoped_refptr(this)));
   } else {
     CancelOnMessageLoopThread();
   }
 }
 
 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
-  DCHECK(message_loop()->BelongsToCurrentThread());
+  DCHECK(task_runner()->BelongsToCurrentThread());
   set_cancelled();
 
   if (handle_ != INVALID_HANDLE_VALUE)
diff --git a/base/files/file_proxy.cc b/base/files/file_proxy.cc
index 53b14fe..f995735 100644
--- a/base/files/file_proxy.cc
+++ b/base/files/file_proxy.cc
@@ -9,7 +9,6 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/task_runner.h"
 #include "base/task_runner_util.h"
 
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc
index dbf1476..df0bbc8 100644
--- a/base/files/file_proxy_unittest.cc
+++ b/base/files/file_proxy_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -79,7 +78,7 @@
   }
 
   TaskRunner* file_task_runner() const {
-    return file_thread_.message_loop_proxy().get();
+    return file_thread_.task_runner().get();
   }
   const FilePath& test_dir_path() const { return dir_.path(); }
   const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
diff --git a/base/files/file_util_proxy_unittest.cc b/base/files/file_util_proxy_unittest.cc
index 5eb6819..7408369 100644
--- a/base/files/file_util_proxy_unittest.cc
+++ b/base/files/file_util_proxy_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,7 +39,7 @@
 
  protected:
   TaskRunner* file_task_runner() const {
-    return file_thread_.message_loop_proxy().get();
+    return file_thread_.task_runner().get();
   }
   const FilePath& test_dir_path() const { return dir_.path(); }
   const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 47b0b09..814fc7b 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -51,6 +51,12 @@
                  << " : " << message;
 }
 
+// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
+bool WriteScopedStringToFileAtomically(const FilePath& path,
+                                       scoped_ptr<std::string> data) {
+  return ImportantFileWriter::WriteFileAtomically(path, *data);
+}
+
 }  // namespace
 
 // static
@@ -124,7 +130,7 @@
       commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
       weak_factory_(this) {
   DCHECK(CalledOnValidThread());
-  DCHECK(task_runner_.get());
+  DCHECK(task_runner_);
 }
 
 ImportantFileWriter::~ImportantFileWriter() {
@@ -139,9 +145,9 @@
   return timer_.IsRunning();
 }
 
-void ImportantFileWriter::WriteNow(const std::string& data) {
+void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
   DCHECK(CalledOnValidThread());
-  if (data.length() > static_cast<size_t>(kint32max)) {
+  if (data->length() > static_cast<size_t>(kint32max)) {
     NOTREACHED();
     return;
   }
@@ -149,13 +155,14 @@
   if (HasPendingWrite())
     timer_.Stop();
 
-  if (!PostWriteTask(data)) {
+  auto task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data));
+  if (!PostWriteTask(task)) {
     // Posting the task to background message loop is not expected
     // to fail, but if it does, avoid losing data and just hit the disk
     // on the current thread.
     NOTREACHED();
 
-    WriteFileAtomically(path_, data);
+    task.Run();
   }
 }
 
@@ -173,9 +180,9 @@
 
 void ImportantFileWriter::DoScheduledWrite() {
   DCHECK(serializer_);
-  std::string data;
-  if (serializer_->SerializeData(&data)) {
-    WriteNow(data);
+  scoped_ptr<std::string> data(new std::string);
+  if (serializer_->SerializeData(data.get())) {
+    WriteNow(data.Pass());
   } else {
     DLOG(WARNING) << "failed to serialize data to be saved in "
                   << path_.value().c_str();
@@ -189,7 +196,7 @@
   on_next_successful_write_ = on_next_successful_write;
 }
 
-bool ImportantFileWriter::PostWriteTask(const std::string& data) {
+bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
   // TODO(gab): This code could always use PostTaskAndReplyWithResult and let
   // ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but
   // PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and
@@ -199,16 +206,13 @@
     return base::PostTaskAndReplyWithResult(
         task_runner_.get(),
         FROM_HERE,
-        MakeCriticalClosure(
-            Bind(&ImportantFileWriter::WriteFileAtomically, path_, data)),
+        MakeCriticalClosure(task),
         Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
              weak_factory_.GetWeakPtr()));
   }
   return task_runner_->PostTask(
       FROM_HERE,
-      MakeCriticalClosure(
-          Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
-               path_, data)));
+      MakeCriticalClosure(base::Bind(IgnoreResult(task))));
 }
 
 void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index 9ead9c1..99f1a7c 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -78,7 +78,7 @@
 
   // Save |data| to target filename. Does not block. If there is a pending write
   // scheduled by ScheduleWrite, it is cancelled.
-  void WriteNow(const std::string& data);
+  void WriteNow(scoped_ptr<std::string> data);
 
   // Schedule a save to target filename. Data will be serialized and saved
   // to disk after the commit interval. If another ScheduleWrite is issued
@@ -106,7 +106,7 @@
 
  private:
   // Helper method for WriteNow().
-  bool PostWriteTask(const std::string& data);
+  bool PostWriteTask(const Callback<bool()>& task);
 
   // If |result| is true and |on_next_successful_write_| is set, invokes
   // |on_successful_write_| and then resets it; no-ops otherwise.
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index 98eaee8..d376cdc 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -9,9 +9,11 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -97,10 +99,10 @@
 };
 
 TEST_F(ImportantFileWriterTest, Basic) {
-  ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   EXPECT_FALSE(PathExists(writer.path()));
   EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
-  writer.WriteNow("foo");
+  writer.WriteNow(make_scoped_ptr(new std::string("foo")));
   RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
@@ -109,11 +111,11 @@
 }
 
 TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
-  ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   EXPECT_FALSE(PathExists(writer.path()));
   EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
   successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
-  writer.WriteNow("foo");
+  writer.WriteNow(make_scoped_ptr(new std::string("foo")));
   RunLoop().RunUntilIdle();
 
   // Confirm that the observer is invoked.
@@ -124,7 +126,7 @@
   // Confirm that re-installing the observer works for another write.
   EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
   successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
-  writer.WriteNow("bar");
+  writer.WriteNow(make_scoped_ptr(new std::string("bar")));
   RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
@@ -134,7 +136,7 @@
   // Confirm that writing again without re-installing the observer doesn't
   // result in a notification.
   EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
-  writer.WriteNow("baz");
+  writer.WriteNow(make_scoped_ptr(new std::string("baz")));
   RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
@@ -143,15 +145,14 @@
 }
 
 TEST_F(ImportantFileWriterTest, ScheduleWrite) {
-  ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
   EXPECT_FALSE(writer.HasPendingWrite());
   DataSerializer serializer("foo");
   writer.ScheduleWrite(&serializer);
   EXPECT_TRUE(writer.HasPendingWrite());
-  MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      MessageLoop::QuitWhenIdleClosure(),
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
       TimeDelta::FromMilliseconds(100));
   MessageLoop::current()->Run();
   EXPECT_FALSE(writer.HasPendingWrite());
@@ -160,15 +161,14 @@
 }
 
 TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
-  ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   EXPECT_FALSE(writer.HasPendingWrite());
   DataSerializer serializer("foo");
   writer.ScheduleWrite(&serializer);
   EXPECT_TRUE(writer.HasPendingWrite());
   writer.DoScheduledWrite();
-  MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      MessageLoop::QuitWhenIdleClosure(),
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
       TimeDelta::FromMilliseconds(100));
   MessageLoop::current()->Run();
   EXPECT_FALSE(writer.HasPendingWrite());
@@ -177,15 +177,14 @@
 }
 
 TEST_F(ImportantFileWriterTest, BatchingWrites) {
-  ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
   DataSerializer foo("foo"), bar("bar"), baz("baz");
   writer.ScheduleWrite(&foo);
   writer.ScheduleWrite(&bar);
   writer.ScheduleWrite(&baz);
-  MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      MessageLoop::QuitWhenIdleClosure(),
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
       TimeDelta::FromMilliseconds(100));
   MessageLoop::current()->Run();
   ASSERT_TRUE(PathExists(writer.path()));
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index 76eaa62..ede6467 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -19,6 +19,9 @@
 #include "base/strings/sys_string_conversions.h"
 #include "third_party/icu/source/common/unicode/putil.h"
 #include "third_party/icu/source/common/unicode/udata.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
 
 #if defined(OS_MACOSX)
 #include "base/mac/foundation_util.h"
@@ -91,6 +94,7 @@
   g_called_once = true;
 #endif
 
+  bool result;
 #if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
   // We expect to find the ICU data module alongside the current module.
   FilePath data_path;
@@ -112,10 +116,10 @@
 
   UErrorCode err = U_ZERO_ERROR;
   udata_setCommonData(reinterpret_cast<void*>(addr), &err);
-  return err == U_ZERO_ERROR;
+  result = (err == U_ZERO_ERROR);
 #elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
   // The ICU data is statically linked.
-  return true;
+  result = true;
 #elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
   // If the ICU data directory is set, ICU won't actually load the data until
   // it is needed.  This can fail if the process is sandboxed at that time.
@@ -174,11 +178,22 @@
   }
   UErrorCode err = U_ZERO_ERROR;
   udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+  result = (err == U_ZERO_ERROR);
 #if defined(OS_WIN)
-  CHECK(err == U_ZERO_ERROR);  // TODO(scottmg): http://crbug.com/445616
+  CHECK(result);  // TODO(scottmg): http://crbug.com/445616
 #endif
-  return err == U_ZERO_ERROR;
 #endif
+
+// To respond to the timezone change properly, the default timezone
+// cache in ICU has to be populated on starting up.
+// TODO(jungshik): Some callers do not care about tz at all. If necessary,
+// add a boolean argument to this function to init'd the default tz only
+// when requested.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  if (result)
+    scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+  return result;
 }
 #endif
 
diff --git a/base/mac/launch_services_util.h b/base/mac/launch_services_util.h
index 0c52ca9..0e64316 100644
--- a/base/mac/launch_services_util.h
+++ b/base/mac/launch_services_util.h
@@ -5,7 +5,7 @@
 #ifndef BASE_MAC_LAUNCH_SERVICES_UTIL_H_
 #define BASE_MAC_LAUNCH_SERVICES_UTIL_H_
 
-#include <ApplicationServices/ApplicationServices.h>
+#include <CoreServices/CoreServices.h>
 
 #include "base/base_export.h"
 #include "base/command_line.h"
diff --git a/base/mac/memory_pressure_monitor_mac.cc b/base/mac/memory_pressure_monitor_mac.cc
new file mode 100644
index 0000000..81727bb
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac.cc
@@ -0,0 +1,76 @@
+// 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/memory_pressure_monitor_mac.h"
+
+#include <dlfcn.h>
+#include <sys/sysctl.h>
+
+#include "base/mac/mac_util.h"
+
+namespace base {
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorMac::MemoryPressureLevelForMacMemoryPressure(
+    int mac_memory_pressure) {
+  switch (mac_memory_pressure) {
+    case DISPATCH_MEMORYPRESSURE_NORMAL:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+    case DISPATCH_MEMORYPRESSURE_WARN:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+    case DISPATCH_MEMORYPRESSURE_CRITICAL:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+  }
+  return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void MemoryPressureMonitorMac::NotifyMemoryPressureChanged(
+    dispatch_source_s* event_source) {
+  int mac_memory_pressure = dispatch_source_get_data(event_source);
+  MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
+      MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+  MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
+MemoryPressureMonitorMac::MemoryPressureMonitorMac()
+  : memory_level_event_source_(nullptr) {
+  // _dispatch_source_type_memorypressure is not available prior to 10.9.
+  dispatch_source_type_t dispatch_source_memorypressure =
+      static_cast<dispatch_source_type_t>
+          (dlsym(RTLD_NEXT, "_dispatch_source_type_memorypressure"));
+  if (dispatch_source_memorypressure) {
+    // The MemoryPressureListener doesn't want to know about transitions to
+    // MEMORY_PRESSURE_LEVEL_NONE so don't watch for
+    // DISPATCH_MEMORYPRESSURE_NORMAL notifications.
+    memory_level_event_source_.reset(
+        dispatch_source_create(dispatch_source_memorypressure, 0,
+                               DISPATCH_MEMORYPRESSURE_WARN |
+                                   DISPATCH_MEMORYPRESSURE_CRITICAL,
+                               dispatch_get_global_queue(
+                                   DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
+
+    dispatch_source_set_event_handler(memory_level_event_source_.get(), ^{
+        NotifyMemoryPressureChanged(memory_level_event_source_.get());
+    });
+    dispatch_retain(memory_level_event_source_.get());
+    dispatch_resume(memory_level_event_source_.get());
+  }
+}
+
+MemoryPressureMonitorMac::~MemoryPressureMonitorMac() {
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorMac::GetCurrentPressureLevel() const {
+  if (base::mac::IsOSMountainLionOrEarlier()) {
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+  }
+  int mac_memory_pressure;
+  size_t length = sizeof(int);
+  sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure,
+               &length, nullptr, 0);
+  return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+}
+
+}  // namespace base
diff --git a/base/mac/memory_pressure_monitor_mac.h b/base/mac/memory_pressure_monitor_mac.h
new file mode 100644
index 0000000..aebdd65
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac.h
@@ -0,0 +1,62 @@
+// 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_MEMORY_PRESSURE_MONITOR_MAC_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+
+// The following was added to <dispatch/source.h> after 10.8.
+// TODO(shrike): Remove the DISPATCH_MEMORYPRESSURE_NORMAL ifndef once builders
+// reach 10.9 or higher.
+#ifndef DISPATCH_MEMORYPRESSURE_NORMAL
+
+#define DISPATCH_MEMORYPRESSURE_NORMAL    0x01
+#define DISPATCH_MEMORYPRESSURE_WARN      0x02
+#define DISPATCH_MEMORYPRESSURE_CRITICAL  0x04
+
+#endif  // DISPATCH_MEMORYPRESSURE_NORMAL
+
+namespace base {
+
+class TestMemoryPressureMonitorMac;
+
+struct DispatchSourceSDeleter {
+  void operator()(dispatch_source_s* ptr) {
+    dispatch_source_cancel(ptr);
+    dispatch_release(ptr);
+  }
+};
+
+// Declares the interface for the Mac MemoryPressureMonitor, which reports
+// memory pressure events and status.
+class BASE_EXPORT MemoryPressureMonitorMac : public MemoryPressureMonitor {
+ public:
+  using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+  MemoryPressureMonitorMac();
+  ~MemoryPressureMonitorMac() override;
+
+  // Returns the currently-observed memory pressure.
+  MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+ private:
+  friend TestMemoryPressureMonitorMac;
+
+  static MemoryPressureLevel
+      MemoryPressureLevelForMacMemoryPressure(int mac_memory_pressure);
+  static void NotifyMemoryPressureChanged(dispatch_source_s* event_source);
+
+  scoped_ptr<dispatch_source_s, DispatchSourceSDeleter>
+      memory_level_event_source_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitorMac);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
diff --git a/base/mac/memory_pressure_monitor_mac_unittest.cc b/base/mac/memory_pressure_monitor_mac_unittest.cc
new file mode 100644
index 0000000..24ee09a
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/memory_pressure_monitor_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class TestMemoryPressureMonitorMac : public MemoryPressureMonitorMac {
+ public:
+  using MemoryPressureMonitorMac::MemoryPressureLevelForMacMemoryPressure;
+
+  TestMemoryPressureMonitorMac() { }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitorMac);
+};
+
+TEST(TestMemoryPressureMonitorMac, MemoryPressureFromMacMemoryPressure) {
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_NORMAL));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_WARN));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_CRITICAL));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(0));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(3));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(5));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(-1));
+}
+
+TEST(TestMemoryPressureMonitorMac, CurrentMemoryPressure) {
+  TestMemoryPressureMonitorMac monitor;
+  MemoryPressureListener::MemoryPressureLevel memory_pressure =
+      monitor.GetCurrentPressureLevel();
+  EXPECT_TRUE(memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE ||
+              memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE ||
+              memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
+}  // namespace base
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
index 8814b51..836bdcc 100644
--- a/base/mac/scoped_nsobject.h
+++ b/base/mac/scoped_nsobject.h
@@ -5,10 +5,16 @@
 #ifndef BASE_MAC_SCOPED_NSOBJECT_H_
 #define BASE_MAC_SCOPED_NSOBJECT_H_
 
-#import <Foundation/Foundation.h>
+// Include NSObject.h directly because Foundation.h pulls in many dependencies.
+// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
+// singled out because it is most typically included from other header files.
+#import <Foundation/NSObject.h>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 
+@class NSAutoreleasePool;
+
 namespace base {
 
 // scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 25d937e..d7be320 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -18,16 +18,91 @@
 
 #include "base/base_export.h"
 
+// ----------------------------------------------------------------------------
+// Either define or forward declare classes only available in OSX 10.7+.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface CWChannel : NSObject
+@end
+
+@interface CBPeripheral : NSObject
+@end
+
+@interface CBCentralManager : NSObject
+@end
+
+@interface CBUUID : NSObject
+@end
+
+#else
+
+@class CWChannel;
+@class CBPeripheral;
+@class CBCentralManager;
+@class CBUUID;
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+@interface NSUUID : NSObject
+@end
+
+#else
+
+@class NSUUID;
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+// NSProgress is public API in 10.9, but a version of it exists and is usable
+// in 10.8.
+@interface NSProgress : NSObject
+@end
+
+@interface NSAppearance : NSObject
+@end
+
+#else
+
+@class NSProgress;
+@class NSAppearance;
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity : NSObject
+@end
+
+#else
+
+@class NSUserActivity;
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Define typedefs, enums, and protocols not available in the version of the
+// OSX SDK being compiled against.
+// ----------------------------------------------------------------------------
+
 #if !defined(MAC_OS_X_VERSION_10_7) || \
     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
 
 enum {
-  NSEventPhaseNone        = 0, // event not associated with a phase.
-  NSEventPhaseBegan       = 0x1 << 0,
-  NSEventPhaseStationary  = 0x1 << 1,
-  NSEventPhaseChanged     = 0x1 << 2,
-  NSEventPhaseEnded       = 0x1 << 3,
-  NSEventPhaseCancelled   = 0x1 << 4
+  NSEventPhaseNone = 0,  // event not associated with a phase.
+  NSEventPhaseBegan = 0x1 << 0,
+  NSEventPhaseStationary = 0x1 << 1,
+  NSEventPhaseChanged = 0x1 << 2,
+  NSEventPhaseEnded = 0x1 << 3,
+  NSEventPhaseCancelled = 0x1 << 4
 };
 typedef NSUInteger NSEventPhase;
 
@@ -65,9 +140,139 @@
 };
 typedef NSUInteger NSWindowButton;
 
+enum CWChannelBand {
+  kCWChannelBandUnknown = 0,
+  kCWChannelBand2GHz = 1,
+  kCWChannelBand5GHz = 2,
+};
+
+enum {
+  kCWSecurityNone = 0,
+  kCWSecurityWEP = 1,
+  kCWSecurityWPAPersonal = 2,
+  kCWSecurityWPAPersonalMixed = 3,
+  kCWSecurityWPA2Personal = 4,
+  kCWSecurityPersonal = 5,
+  kCWSecurityDynamicWEP = 6,
+  kCWSecurityWPAEnterprise = 7,
+  kCWSecurityWPAEnterpriseMixed = 8,
+  kCWSecurityWPA2Enterprise = 9,
+  kCWSecurityEnterprise = 10,
+  kCWSecurityUnknown = NSIntegerMax,
+};
+
+typedef NSInteger CWSecurity;
+
+enum {
+  kBluetoothFeatureLESupportedController = (1 << 6L),
+};
+
+@protocol IOBluetoothDeviceInquiryDelegate
+- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
+- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
+                          device:(IOBluetoothDevice*)device;
+- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
+                        error:(IOReturn)error
+                      aborted:(BOOL)aborted;
+@end
+
+@protocol NSWindowDelegateFullScreenAdditions
+- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
+- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
+@end
+
+enum {
+  CBPeripheralStateDisconnected = 0,
+  CBPeripheralStateConnecting,
+  CBPeripheralStateConnected,
+};
+typedef NSInteger CBPeripheralState;
+
+enum {
+  CBCentralManagerStateUnknown = 0,
+  CBCentralManagerStateResetting,
+  CBCentralManagerStateUnsupported,
+  CBCentralManagerStateUnauthorized,
+  CBCentralManagerStatePoweredOff,
+  CBCentralManagerStatePoweredOn,
+};
+typedef NSInteger CBCentralManagerState;
+
+@protocol CBCentralManagerDelegate;
+
+@protocol CBCentralManagerDelegate<NSObject>
+- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
+- (void)centralManager:(CBCentralManager*)central
+    didDiscoverPeripheral:(CBPeripheral*)peripheral
+        advertisementData:(NSDictionary*)advertisementData
+                     RSSI:(NSNumber*)RSSI;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+enum { NSEventPhaseMayBegin = 0x1 << 5 };
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+enum {
+  NSWindowOcclusionStateVisible = 1UL << 1,
+};
+typedef NSUInteger NSWindowOcclusionState;
+
+enum { NSWorkspaceLaunchWithErrorPresentation = 0x00000040 };
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+// ----------------------------------------------------------------------------
+// Define NSStrings only available in newer versions of the OSX SDK to force
+// them to be statically linked.
+// ----------------------------------------------------------------------------
+
+extern "C" {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+BASE_EXPORT extern NSString* const NSWindowWillEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowWillExitFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidExitFullScreenNotification;
+BASE_EXPORT extern NSString* const
+    NSWindowDidChangeBackingPropertiesNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataServiceDataKey;
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern NSString* const NSWindowDidChangeOcclusionStateNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataIsConnectable;
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+BASE_EXPORT extern NSString* const NSUserActivityTypeBrowsingWeb;
+BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
+#endif  // MAC_OS_X_VERSION_10_10
+}  // extern "C"
+
+// ----------------------------------------------------------------------------
+// If compiling against an older version of the OSX SDK, declare functions that
+// are available in newer versions of the OSX SDK. If compiling against a newer
+// version of the OSX SDK, redeclare those same functions to suppress
+// -Wpartial-availability warnings.
+// ----------------------------------------------------------------------------
+
+// Once Chrome no longer supports OSX 10.6, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+
 @interface NSEvent (LionSDK)
 + (BOOL)isSwipeTrackingFromScrollEventsEnabled;
-
 - (NSEventPhase)momentumPhase;
 - (NSEventPhase)phase;
 - (BOOL)hasPreciseScrollingDeltas;
@@ -79,10 +284,8 @@
                       usingHandler:(void (^)(CGFloat gestureAmount,
                                              NSEventPhase phase,
                                              BOOL isComplete,
-                                             BOOL *stop))trackingHandler;
-
+                                             BOOL* stop))trackingHandler;
 - (BOOL)isDirectionInvertedFromDevice;
-
 @end
 
 @interface NSApplication (LionSDK)
@@ -113,9 +316,9 @@
 @end
 
 @interface NSAnimationContext (LionSDK)
-+ (void)runAnimationGroup:(void (^)(NSAnimationContext *context))changes
++ (void)runAnimationGroup:(void (^)(NSAnimationContext* context))changes
         completionHandler:(void (^)(void))completionHandler;
-@property(copy) void(^completionHandler)(void);
+@property(copy) void (^completionHandler)(void);
 @end
 
 @interface NSView (LionSDK)
@@ -139,37 +342,13 @@
 - (BOOL)associateToNetwork:(CWNetwork*)network
                   password:(NSString*)password
                      error:(NSError**)error;
-- (NSSet*)scanForNetworksWithName:(NSString*)networkName
-                            error:(NSError**)error;
+- (NSSet*)scanForNetworksWithName:(NSString*)networkName error:(NSError**)error;
 @end
 
-enum CWChannelBand {
-  kCWChannelBandUnknown = 0,
-  kCWChannelBand2GHz = 1,
-  kCWChannelBand5GHz = 2,
-};
-
-@interface CWChannel : NSObject
+@interface CWChannel (LionSDK)
 @property(readonly) CWChannelBand channelBand;
 @end
 
-enum {
-   kCWSecurityNone = 0,
-   kCWSecurityWEP = 1,
-   kCWSecurityWPAPersonal = 2,
-   kCWSecurityWPAPersonalMixed = 3,
-   kCWSecurityWPA2Personal = 4,
-   kCWSecurityPersonal = 5,
-   kCWSecurityDynamicWEP = 6,
-   kCWSecurityWPAEnterprise = 7,
-   kCWSecurityWPAEnterpriseMixed = 8,
-   kCWSecurityWPA2Enterprise = 9,
-   kCWSecurityEnterprise = 10,
-   kCWSecurityUnknown = NSIntegerMax,
-};
-
-typedef NSInteger CWSecurity;
-
 @interface CWNetwork (LionSDK)
 @property(readonly) CWChannel* wlanChannel;
 @property(readonly) NSInteger rssiValue;
@@ -181,19 +360,6 @@
 - (BluetoothHCIPowerState)powerState;
 @end
 
-enum {
-  kBluetoothFeatureLESupportedController = (1 << 6L),
-};
-
-@protocol IOBluetoothDeviceInquiryDelegate
-- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
-- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
-                          device:(IOBluetoothDevice*)device;
-- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
-                        error:(IOReturn)error
-                      aborted:(BOOL)aborted;
-@end
-
 @interface IOBluetoothL2CAPChannel (LionSDK)
 @property(readonly) BluetoothL2CAPMTU outgoingMTU;
 @end
@@ -207,46 +373,13 @@
 - (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids;
 @end
 
-BASE_EXPORT extern "C" NSString* const NSWindowWillEnterFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowWillExitFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowDidEnterFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowDidExitFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const
-    NSWindowDidChangeBackingPropertiesNotification;
-
-@protocol NSWindowDelegateFullScreenAdditions
-- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
-- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
-@end
-
-BASE_EXPORT extern "C" NSString* const CBAdvertisementDataServiceDataKey;
-
-enum {
-  CBPeripheralStateDisconnected = 0,
-  CBPeripheralStateConnecting,
-  CBPeripheralStateConnected,
-};
-typedef NSInteger CBPeripheralState;
-
-@interface CBPeripheral : NSObject
+@interface CBPeripheral (LionSDK)
 @property(readonly, nonatomic) CFUUIDRef UUID;
 @property(retain, readonly) NSString* name;
 @property(readonly) BOOL isConnected;
 @end
 
-enum {
-  CBCentralManagerStateUnknown = 0,
-  CBCentralManagerStateResetting,
-  CBCentralManagerStateUnsupported,
-  CBCentralManagerStateUnauthorized,
-  CBCentralManagerStatePoweredOff,
-  CBCentralManagerStatePoweredOn,
-};
-typedef NSInteger CBCentralManagerState;
-
-@protocol CBCentralManagerDelegate;
-
-@interface CBCentralManager : NSObject
+@interface CBCentralManager (LionSDK)
 @property(readonly) CBCentralManagerState state;
 - (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate
                  queue:(dispatch_queue_t)queue;
@@ -255,33 +388,23 @@
 - (void)stopScan;
 @end
 
-@protocol CBCentralManagerDelegate<NSObject>
-- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
-- (void)centralManager:(CBCentralManager*)central
-    didDiscoverPeripheral:(CBPeripheral*)peripheral
-        advertisementData:(NSDictionary*)advertisementData
-                     RSSI:(NSNumber*)RSSI;
-@end
-
-@interface CBUUID : NSObject
+@interface CBUUID (LionSDK)
 @property(nonatomic, readonly) NSData* data;
 + (CBUUID*)UUIDWithString:(NSString*)theString;
 @end
 
 #endif  // MAC_OS_X_VERSION_10_7
 
+// Once Chrome no longer supports OSX 10.7, everything within this preprocessor
+// block can be removed.
 #if !defined(MAC_OS_X_VERSION_10_8) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
-
-enum {
-  NSEventPhaseMayBegin    = 0x1 << 5
-};
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
 
 @interface NSColor (MountainLionSDK)
 - (CGColorRef)CGColor;
 @end
 
-@interface NSUUID : NSObject
+@interface NSUUID (MountainLionSDK)
 - (NSString*)UUIDString;
 @end
 
@@ -291,36 +414,34 @@
 
 #endif  // MAC_OS_X_VERSION_10_8
 
-
+// Once Chrome no longer supports OSX 10.8, everything within this preprocessor
+// block can be removed.
 #if !defined(MAC_OS_X_VERSION_10_9) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
 
-// NSProgress is public API in 10.9, but a version of it exists and is usable
-// in 10.8.
-
-@interface NSProgress : NSObject
+@interface NSProgress (MavericksSDK)
 
 - (instancetype)initWithParent:(NSProgress*)parentProgressOrNil
                       userInfo:(NSDictionary*)userInfoOrNil;
-@property (copy) NSString* kind;
+@property(copy) NSString* kind;
 
 @property int64_t totalUnitCount;
 @property int64_t completedUnitCount;
 
-@property (getter=isCancellable) BOOL cancellable;
-@property (getter=isPausable) BOOL pausable;
-@property (readonly, getter=isCancelled) BOOL cancelled;
-@property (readonly, getter=isPaused) BOOL paused;
-@property (copy) void (^cancellationHandler)(void);
-@property (copy) void (^pausingHandler)(void);
+@property(getter=isCancellable) BOOL cancellable;
+@property(getter=isPausable) BOOL pausable;
+@property(readonly, getter=isCancelled) BOOL cancelled;
+@property(readonly, getter=isPaused) BOOL paused;
+@property(copy) void (^cancellationHandler)(void);
+@property(copy) void (^pausingHandler)(void);
 - (void)cancel;
 - (void)pause;
 
 - (void)setUserInfoObject:(id)objectOrNil forKey:(NSString*)key;
 - (NSDictionary*)userInfo;
 
-@property (readonly, getter=isIndeterminate) BOOL indeterminate;
-@property (readonly) double fractionCompleted;
+@property(readonly, getter=isIndeterminate) BOOL indeterminate;
+@property(readonly) double fractionCompleted;
 
 - (void)publish;
 - (void)unpublish;
@@ -331,72 +452,35 @@
 + (BOOL)screensHaveSeparateSpaces;
 @end
 
-// NSAppearance is a new class in the 10.9 SDK. New classes cannot be
-// forward-declared because they also require an @implementation, which would
-// produce conflicting linkage. Instead, just declare the necessary pieces of
-// the interface as a protocol, and treat objects of this type as id.
-@protocol CrNSAppearance<NSObject>
-+ (id<NSObject>)appearanceNamed:(NSString*)name;
-@end
-
 @interface NSView (MavericksSDK)
 - (void)setCanDrawSubviewsIntoLayer:(BOOL)flag;
-- (id<CrNSAppearance>)effectiveAppearance;
+- (NSAppearance*)effectiveAppearance;
 @end
 
-enum {
-  NSWindowOcclusionStateVisible = 1UL << 1,
-};
-typedef NSUInteger NSWindowOcclusionState;
-
 @interface NSWindow (MavericksSDK)
 - (NSWindowOcclusionState)occlusionState;
 @end
 
-
-BASE_EXPORT extern "C" NSString* const
-    NSWindowDidChangeOcclusionStateNotification;
-
-enum {
-  NSWorkspaceLaunchWithErrorPresentation = 0x00000040
-};
+@interface NSAppearance (MavericksSDK)
++ (id<NSObject>)appearanceNamed:(NSString*)name;
+@end
 
 @interface CBPeripheral (MavericksSDK)
 @property(readonly, nonatomic) NSUUID* identifier;
 @end
 
-BASE_EXPORT extern "C" NSString* const CBAdvertisementDataIsConnectable;
-
-#else  // !MAC_OS_X_VERSION_10_9
-
-typedef enum {
-   kCWSecurityModeOpen = 0,
-   kCWSecurityModeWEP,
-   kCWSecurityModeWPA_PSK,
-   kCWSecurityModeWPA2_PSK,
-   kCWSecurityModeWPA_Enterprise,
-   kCWSecurityModeWPA2_Enterprise,
-   kCWSecurityModeWPS,
-   kCWSecurityModeDynamicWEP
-} CWSecurityMode;
-
-@interface CWNetwork (SnowLeopardSDK)
-@property(readonly) NSNumber* rssi;
-@property(readonly) NSNumber* securityMode;
-@end
-
-BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
-
 #endif  // MAC_OS_X_VERSION_10_9
 
+// Once Chrome no longer supports OSX 10.9, everything within this preprocessor
+// block can be removed.
 #if !defined(MAC_OS_X_VERSION_10_10) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
 
-@interface NSUserActivity : NSObject
+@interface NSUserActivity (YosemiteSDK)
 
-@property (readonly, copy) NSString* activityType;
-@property (copy) NSDictionary* userInfo;
-@property (copy) NSURL* webpageURL;
+@property(readonly, copy) NSString* activityType;
+@property(copy) NSDictionary* userInfo;
+@property(copy) NSURL* webpageURL;
 
 - (instancetype)initWithActivityType:(NSString*)activityType;
 - (void)becomeCurrent;
@@ -404,14 +488,48 @@
 
 @end
 
-BASE_EXPORT extern "C" NSString* const NSUserActivityTypeBrowsingWeb;
-
-BASE_EXPORT extern "C" NSString* const NSAppearanceNameVibrantDark;
-
 @interface CBUUID (YosemiteSDK)
 - (NSString*)UUIDString;
 @end
 
 #endif  // MAC_OS_X_VERSION_10_10
 
+// ----------------------------------------------------------------------------
+// Chrome uses -[CWNetwork securityMode] and -[CWNetwork rssi] on OSX 10.6. The
+// former method relies on the enum CWSecurityMode which was removed in the OSX
+// 10.9 SDK. In order for Chrome to compile against an OSX 10.9+ SDK, Chrome
+// must define this enum. Chrome must also declare these methods.
+//
+// These declarations and definitions will not be necessary once Chrome no
+// longer runs on OSX 10.6.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6
+typedef enum {
+  kCWSecurityModeOpen = 0,
+  kCWSecurityModeWEP,
+  kCWSecurityModeWPA_PSK,
+  kCWSecurityModeWPA2_PSK,
+  kCWSecurityModeWPA_Enterprise,
+  kCWSecurityModeWPA2_Enterprise,
+  kCWSecurityModeWPS,
+  kCWSecurityModeDynamicWEP
+} CWSecurityMode;
+
+@interface CWNetwork (SnowLeopardSDK)
+@property(readonly) NSNumber* rssi;
+@property(readonly) NSNumber* securityMode;
+@end
+#endif
+
+// ----------------------------------------------------------------------------
+// The symbol for kCWSSIDDidChangeNotification is available in the
+// CoreWLAN.framework for OSX versions 10.6 through 10.10. The symbol is not
+// declared in the OSX 10.9+ SDK, so when compiling against an OSX 10.9+ SDK,
+// declare the symbol.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
+#endif
 #endif  // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
diff --git a/base/mac/sdk_forward_declarations.mm b/base/mac/sdk_forward_declarations.mm
index 4edc710..347e87c 100644
--- a/base/mac/sdk_forward_declarations.mm
+++ b/base/mac/sdk_forward_declarations.mm
@@ -4,10 +4,8 @@
 
 #include "base/mac/sdk_forward_declarations.h"
 
-// Replicate specific 10.7 SDK declarations for building with prior SDKs.
 #if !defined(MAC_OS_X_VERSION_10_7) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
 NSString* const NSWindowWillEnterFullScreenNotification =
     @"NSWindowWillEnterFullScreenNotification";
 
@@ -24,27 +22,20 @@
     @"NSWindowDidChangeBackingPropertiesNotification";
 
 NSString* const CBAdvertisementDataServiceDataKey = @"kCBAdvDataServiceData";
-
 #endif  // MAC_OS_X_VERSION_10_7
 
-// Replicate specific 10.9 SDK declarations for building with prior SDKs.
 #if !defined(MAC_OS_X_VERSION_10_9) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
-
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
 NSString* const NSWindowDidChangeOcclusionStateNotification =
     @"NSWindowDidChangeOcclusionStateNotification";
 
 NSString* const CBAdvertisementDataIsConnectable = @"kCBAdvDataIsConnectable";
-
 #endif  // MAC_OS_X_VERSION_10_9
 
-// Replicate specific 10.10 SDK declarations for building with prior SDKs.
 #if !defined(MAC_OS_X_VERSION_10_10) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
-
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
 NSString* const NSUserActivityTypeBrowsingWeb =
     @"NSUserActivityTypeBrowsingWeb";
 
 NSString* const NSAppearanceNameVibrantDark = @"NSAppearanceNameVibrantDark";
-
 #endif  // MAC_OS_X_VERSION_10_10
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
index 139a1ed..6a109e8 100644
--- a/base/memory/ref_counted_delete_on_message_loop.h
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -32,6 +32,7 @@
 //   ~Foo();
 // };
 
+// TODO(skyostil): Rename this to RefCountedDeleteOnTaskRunner.
 template <class T>
 class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
  public:
@@ -42,7 +43,7 @@
   RefCountedDeleteOnMessageLoop(
       const scoped_refptr<SingleThreadTaskRunner>& task_runner)
       : task_runner_(task_runner) {
-    DCHECK(task_runner_.get());
+    DCHECK(task_runner_);
   }
 
   void AddRef() const {
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc
index d89a5c6..20e5c7b 100644
--- a/base/memory/weak_ptr_unittest.cc
+++ b/base/memory/weak_ptr_unittest.cc
@@ -8,8 +8,9 @@
 
 #include "base/bind.h"
 #include "base/debug/leak_annotations.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,9 +26,8 @@
     {
       Thread creator_thread("creator_thread");
       creator_thread.Start();
-      creator_thread.message_loop()->PostTask(
-          FROM_HERE,
-          base::Bind(OffThreadObjectCreator::CreateObject, &result));
+      creator_thread.task_runner()->PostTask(
+          FROM_HERE, base::Bind(OffThreadObjectCreator::CreateObject, &result));
     }
     DCHECK(result);  // We synchronized on thread destruction above.
     return result;
@@ -66,25 +66,23 @@
 
   void CreateArrowFromTarget(Arrow** arrow, Target* target) {
     WaitableEvent completion(true, false);
-    message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
-                   arrow, target, &completion));
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
+                              target, &completion));
     completion.Wait();
   }
 
   void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
     WaitableEvent completion(true, false);
-    message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
-                   arrow, other, &completion));
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
+                              other, &completion));
     completion.Wait();
   }
 
   void DeleteTarget(Target* object) {
     WaitableEvent completion(true, false);
-    message_loop()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
     completion.Wait();
@@ -92,25 +90,23 @@
 
   void CopyAndAssignArrow(Arrow* object) {
     WaitableEvent completion(true, false);
-    message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&BackgroundThread::DoCopyAndAssignArrow,
-                   object, &completion));
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
+                              &completion));
     completion.Wait();
   }
 
   void CopyAndAssignArrowBase(Arrow* object) {
     WaitableEvent completion(true, false);
-    message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
-                   object, &completion));
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
+                              object, &completion));
     completion.Wait();
   }
 
   void DeleteArrow(Arrow* object) {
     WaitableEvent completion(true, false);
-    message_loop()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
     completion.Wait();
@@ -119,9 +115,8 @@
   Target* DeRef(const Arrow* arrow) {
     WaitableEvent completion(true, false);
     Target* result = NULL;
-    message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion));
+    task_runner()->PostTask(FROM_HERE, base::Bind(&BackgroundThread::DoDeRef,
+                                                  arrow, &result, &completion));
     completion.Wait();
     return result;
   }
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index c1ce939..5e9a461 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -44,7 +44,8 @@
       message_loop_(message_loop),
       next_sequence_num_(0),
       message_loop_scheduled_(false),
-      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {
+      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())),
+      is_ready_for_scheduling_(false) {
 }
 
 bool IncomingTaskQueue::AddToIncomingQueue(
@@ -109,6 +110,15 @@
   message_loop_ = NULL;
 }
 
+void IncomingTaskQueue::StartScheduling() {
+  AutoLock lock(incoming_queue_lock_);
+  DCHECK(!is_ready_for_scheduling_);
+  DCHECK(!message_loop_scheduled_);
+  is_ready_for_scheduling_ = true;
+  if (!incoming_queue_.empty())
+    ScheduleWork();
+}
+
 IncomingTaskQueue::~IncomingTaskQueue() {
   // Verify that WillDestroyCurrentMessageLoop() has been called.
   DCHECK(!message_loop_);
@@ -148,19 +158,25 @@
   incoming_queue_.push(*pending_task);
   pending_task->task.Reset();
 
-  if (always_schedule_work_ || (!message_loop_scheduled_ && was_empty)) {
-    // Wake up the message loop.
-    message_loop_->ScheduleWork();
-    // After we've scheduled the message loop, we do not need to do so again
-    // until we know it has processed all of the work in our queue and is
-    // waiting for more work again. The message loop will always attempt to
-    // reload from the incoming queue before waiting again so we clear this flag
-    // in ReloadWorkQueue().
-    message_loop_scheduled_ = true;
+  if (is_ready_for_scheduling_ &&
+      (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) {
+    ScheduleWork();
   }
 
   return true;
 }
 
+void IncomingTaskQueue::ScheduleWork() {
+  DCHECK(is_ready_for_scheduling_);
+  // Wake up the message loop.
+  message_loop_->ScheduleWork();
+  // After we've scheduled the message loop, we do not need to do so again
+  // until we know it has processed all of the work in our queue and is
+  // waiting for more work again. The message loop will always attempt to
+  // reload from the incoming queue before waiting again so we clear this flag
+  // in ReloadWorkQueue().
+  message_loop_scheduled_ = true;
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 72e1f30..7dd1e82 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -53,6 +53,10 @@
   // Disconnects |this| from the parent message loop.
   void WillDestroyCurrentMessageLoop();
 
+  // This should be called when the message loop becomes ready for
+  // scheduling work.
+  void StartScheduling();
+
  private:
   friend class RefCountedThreadSafe<IncomingTaskQueue>;
   virtual ~IncomingTaskQueue();
@@ -66,6 +70,9 @@
   // does not retain |pending_task->task| beyond this function call.
   bool PostPendingTask(PendingTask* pending_task);
 
+  // Wakes up the message loop and schedules work.
+  void ScheduleWork();
+
   // Number of tasks that require high resolution timing. This value is kept
   // so that ReloadWorkQueue() completes in constant time.
   int high_res_task_count_;
@@ -92,6 +99,9 @@
   // if the incoming queue was not empty.
   const bool always_schedule_work_;
 
+  // False until StartScheduling() is called.
+  bool is_ready_for_scheduling_;
+
   DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
 };
 
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index eb0f968..4222c77 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -100,6 +100,10 @@
 }
 #endif  // !defined(OS_NACL_SFI)
 
+scoped_ptr<MessagePump> ReturnPump(scoped_ptr<MessagePump> pump) {
+  return pump;
+}
+
 }  // namespace
 
 //------------------------------------------------------------------------------
@@ -116,41 +120,19 @@
 //------------------------------------------------------------------------------
 
 MessageLoop::MessageLoop(Type type)
-    : type_(type),
-#if defined(OS_WIN)
-      pending_high_res_tasks_(0),
-      in_high_res_mode_(false),
-#endif
-      nestable_tasks_allowed_(true),
-#if defined(OS_WIN)
-      os_modal_loop_(false),
-#endif  // OS_WIN
-      message_histogram_(NULL),
-      run_loop_(NULL) {
-  Init();
-
-  pump_ = CreateMessagePumpForType(type).Pass();
+    : MessageLoop(type, MessagePumpFactoryCallback()) {
+  BindToCurrentThread();
 }
 
 MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
-    : pump_(pump.Pass()),
-      type_(TYPE_CUSTOM),
-#if defined(OS_WIN)
-      pending_high_res_tasks_(0),
-      in_high_res_mode_(false),
-#endif
-      nestable_tasks_allowed_(true),
-#if defined(OS_WIN)
-      os_modal_loop_(false),
-#endif  // OS_WIN
-      message_histogram_(NULL),
-      run_loop_(NULL) {
-  DCHECK(pump_.get());
-  Init();
+    : MessageLoop(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) {
+  BindToCurrentThread();
 }
 
 MessageLoop::~MessageLoop() {
-  DCHECK_EQ(this, current());
+  // current() could be NULL if this message loop is destructed before it is
+  // bound to a thread.
+  DCHECK(current() == this || !current());
 
   // iOS just attaches to the loop, it doesn't Run it.
   // TODO(stuartmorgan): Consider wiring up a Detach().
@@ -299,11 +281,13 @@
 }
 
 void MessageLoop::Run() {
+  DCHECK(pump_);
   RunLoop run_loop;
   run_loop.Run();
 }
 
 void MessageLoop::RunUntilIdle() {
+  DCHECK(pump_);
   RunLoop run_loop;
   run_loop.RunUntilIdle();
 }
@@ -383,13 +367,43 @@
 
 //------------------------------------------------------------------------------
 
-void MessageLoop::Init() {
+scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
+    Type type, MessagePumpFactoryCallback pump_factory) {
+  return make_scoped_ptr(new MessageLoop(type, pump_factory));
+}
+
+MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)
+    : type_(type),
+#if defined(OS_WIN)
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
+#endif
+      nestable_tasks_allowed_(true),
+#if defined(OS_WIN)
+      os_modal_loop_(false),
+#endif  // OS_WIN
+      pump_factory_(pump_factory),
+      message_histogram_(NULL),
+      run_loop_(NULL),
+      incoming_task_queue_(new internal::IncomingTaskQueue(this)),
+      message_loop_proxy_(
+          new internal::MessageLoopProxyImpl(incoming_task_queue_)) {
+  // If type is TYPE_CUSTOM non-null pump_factory must be given.
+  DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
+}
+
+void MessageLoop::BindToCurrentThread() {
+  DCHECK(!pump_);
+  if (!pump_factory_.is_null())
+    pump_ = pump_factory_.Run();
+  else
+    pump_ = CreateMessagePumpForType(type_);
+
   DCHECK(!current()) << "should only have one message loop per thread";
   lazy_tls_ptr.Pointer()->Set(this);
 
-  incoming_task_queue_ = new internal::IncomingTaskQueue(this);
-  message_loop_proxy_ =
-      new internal::MessageLoopProxyImpl(incoming_task_queue_);
+  incoming_task_queue_->StartScheduling();
+  message_loop_proxy_->BindToCurrentThread();
   thread_task_runner_handle_.reset(
       new ThreadTaskRunnerHandle(message_loop_proxy_));
 }
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index fd7596a..f2f89d0 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -114,7 +114,8 @@
   explicit MessageLoop(Type type = TYPE_DEFAULT);
   // Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must
   // be non-NULL.
-  explicit MessageLoop(scoped_ptr<base::MessagePump> pump);
+  explicit MessageLoop(scoped_ptr<MessagePump> pump);
+
   ~MessageLoop() override;
 
   // Returns the MessageLoop object for the current thread, or null if none.
@@ -394,10 +395,6 @@
   // Returns true if the message loop is "idle". Provided for testing.
   bool IsIdleForTesting();
 
-  // Wakes up the message pump. Can be called on any thread. The caller is
-  // responsible for synchronizing ScheduleWork() calls.
-  void ScheduleWork();
-
   // Returns the TaskAnnotator which is used to add debug information to posted
   // tasks.
   debug::TaskAnnotator* task_annotator() { return &task_annotator_; }
@@ -411,9 +408,33 @@
 
  private:
   friend class RunLoop;
+  friend class internal::IncomingTaskQueue;
+  friend class ScheduleWorkTest;
+  friend class Thread;
 
-  // Configures various members for the two constructors.
-  void Init();
+  using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
+
+  // Creates a MessageLoop without binding to a thread.
+  // If |type| is TYPE_CUSTOM non-null |pump_factory| must be also given
+  // to create a message pump for this message loop.  Otherwise a default
+  // message pump for the |type| is created.
+  //
+  // It is valid to call this to create a new message loop on one thread,
+  // and then pass it to the thread where the message loop actually runs.
+  // The message loop's BindToCurrentThread() method must be called on the
+  // 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(
+      Type type,
+      MessagePumpFactoryCallback pump_factory);
+
+  // Common private constructor. Other constructors delegate the initialization
+  // to this constructor.
+  MessageLoop(Type type, MessagePumpFactoryCallback pump_factory);
+
+  // Configure various members and bind this message loop to the current thread.
+  void BindToCurrentThread();
 
   // Invokes the actual run loop using the message pump.
   void RunHandler();
@@ -437,6 +458,10 @@
   // empty.
   void ReloadWorkQueue();
 
+  // Wakes up the message pump. Can be called on any thread. The caller is
+  // responsible for synchronizing ScheduleWork() calls.
+  void ScheduleWork();
+
   // Start recording histogram info about events and action IF it was enabled
   // and IF the statistics recorder can accept a registration of our histogram.
   void StartHistogrammer();
@@ -490,6 +515,10 @@
   bool os_modal_loop_;
 #endif
 
+  // pump_factory_.Run() is called to create a message pump for this loop
+  // if type_ is TYPE_CUSTOM and pump_ is null.
+  MessagePumpFactoryCallback pump_factory_;
+
   std::string thread_name_;
   // A profiling histogram showing the counts of various messages and events.
   HistogramBase* message_histogram_;
diff --git a/base/message_loop/message_loop_proxy.h b/base/message_loop/message_loop_proxy.h
index 88eeac4..d5ecc04 100644
--- a/base/message_loop/message_loop_proxy.h
+++ b/base/message_loop/message_loop_proxy.h
@@ -10,6 +10,18 @@
 #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
diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc
index b7abca3..0da21a0 100644
--- a/base/message_loop/message_loop_proxy_impl.cc
+++ b/base/message_loop/message_loop_proxy_impl.cc
@@ -15,7 +15,12 @@
 MessageLoopProxyImpl::MessageLoopProxyImpl(
     scoped_refptr<IncomingTaskQueue> incoming_queue)
     : incoming_queue_(incoming_queue),
-      valid_thread_id_(PlatformThread::CurrentId()) {
+      valid_thread_id_(kInvalidThreadId) {
+}
+
+void MessageLoopProxyImpl::BindToCurrentThread() {
+  DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
+  valid_thread_id_ = PlatformThread::CurrentId();
 }
 
 bool MessageLoopProxyImpl::PostDelayedTask(
diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h
index 0fe629f..c477320 100644
--- a/base/message_loop/message_loop_proxy_impl.h
+++ b/base/message_loop/message_loop_proxy_impl.h
@@ -24,6 +24,9 @@
   explicit MessageLoopProxyImpl(
       scoped_refptr<IncomingTaskQueue> incoming_queue);
 
+  // Initialize this message loop proxy on the current thread.
+  void BindToCurrentThread();
+
   // MessageLoopProxy implementation
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
index b3e5604..0bf3d0c 100644
--- a/base/message_loop/message_pump_perftest.cc
+++ b/base/message_loop/message_pump_perftest.cc
@@ -20,7 +20,6 @@
 #endif
 
 namespace base {
-namespace {
 
 class ScheduleWorkTest : public testing::Test {
  public:
@@ -224,9 +223,6 @@
 }
 #endif
 
-static void DoNothing() {
-}
-
 class FakeMessagePump : public MessagePump {
  public:
   FakeMessagePump() {}
@@ -289,5 +285,4 @@
   Run(1000, 100);
 }
 
-}  // namespace
 }  // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 23c28d4..39ecc30 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -31,7 +31,6 @@
   g_statistics_recorder_.Get();
 }
 
-
 // static
 bool StatisticsRecorder::IsActive() {
   if (lock_ == NULL)
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 3bef622..b523057 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -88,6 +88,7 @@
   friend class HistogramBaseTest;
   friend class HistogramSnapshotManagerTest;
   friend class HistogramTest;
+  friend class JsonPrefStoreTest;
   friend class SparseHistogramTest;
   friend class StatisticsRecorderTest;
   FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index 5205a5a..e0ce0da 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -14,9 +14,10 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -177,7 +178,7 @@
     base::AutoLock lock(list_lock_);
     for (const auto& entry : observer_lists_) {
       ObserverListContext* context = entry.second;
-      context->loop->PostTask(
+      context->task_runner->PostTask(
           from_here,
           base::Bind(
               &ObserverListThreadSafe<ObserverType>::template NotifyWrapper<
@@ -192,11 +193,9 @@
 
   struct ObserverListContext {
     explicit ObserverListContext(NotificationType type)
-        : loop(base::MessageLoopProxy::current()),
-          list(type) {
-    }
+        : task_runner(base::ThreadTaskRunnerHandle::Get()), list(type) {}
 
-    scoped_refptr<base::MessageLoopProxy> loop;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
     ObserverList<ObserverType> list;
 
    private:
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index ea916b1..2e51e45 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -8,9 +8,10 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/platform_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -107,7 +108,7 @@
 
   void ThreadMain() override {
     loop_ = new MessageLoop();  // Fire up a message loop.
-    loop_->PostTask(
+    loop_->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
     loop_->Run();
@@ -137,13 +138,14 @@
       list_->Notify(FROM_HERE, &Foo::Observe, 10);
     }
 
-    loop_->PostTask(
+    loop_->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
   }
 
   void Quit() {
-    loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+    loop_->task_runner()->PostTask(FROM_HERE,
+                                   MessageLoop::QuitWhenIdleClosure());
   }
 
   void Observe(int x) override {
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
index 60b2bb8..c05141c 100644
--- a/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -10,9 +10,11 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
+#include "base/location.h"
 #include "base/memory/scoped_vector.h"
 #include "base/pickle.h"
 #include "base/posix/unix_domain_socket_linux.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,11 +34,10 @@
 
   // Have the thread send a synchronous message via the socket.
   Pickle request;
-  message_thread.message_loop()->PostTask(
+  message_thread.task_runner()->PostTask(
       FROM_HERE,
-      Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg),
-           fds[1], static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL),
-           request));
+      Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1],
+           static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
 
   // Receive the message.
   ScopedVector<base::ScopedFD> message_fds;
@@ -51,9 +52,8 @@
 
   // Check that the thread didn't get blocked.
   WaitableEvent event(false, false);
-  message_thread.message_loop()->PostTask(
-      FROM_HERE,
-      Bind(&WaitableEvent::Signal, Unretained(&event)));
+  message_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
   ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000)));
 }
 
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
index 47cd424..416e43f 100644
--- a/base/prefs/json_pref_store.cc
+++ b/base/prefs/json_pref_store.cc
@@ -16,9 +16,11 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_filter.h"
 #include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/time/default_clock.h"
 #include "base/values.h"
 
 // Result returned from internal read tasks.
@@ -156,7 +158,8 @@
       pref_filter_(pref_filter.Pass()),
       initialized_(false),
       filtering_in_progress_(false),
-      read_error_(PREF_READ_ERROR_NONE) {
+      read_error_(PREF_READ_ERROR_NONE),
+      write_count_histogram_(writer_.commit_interval(), path_) {
   DCHECK(!path_.empty());
 }
 
@@ -174,7 +177,8 @@
       pref_filter_(pref_filter.Pass()),
       initialized_(false),
       filtering_in_progress_(false),
-      read_error_(PREF_READ_ERROR_NONE) {
+      read_error_(PREF_READ_ERROR_NONE),
+      write_count_histogram_(writer_.commit_interval(), path_) {
   DCHECK(!path_.empty());
 }
 
@@ -394,6 +398,8 @@
 bool JsonPrefStore::SerializeData(std::string* output) {
   DCHECK(CalledOnValidThread());
 
+  write_count_histogram_.RecordWriteOccured();
+
   if (pref_filter_)
     pref_filter_->FilterSerializeData(prefs_.get());
 
@@ -435,3 +441,91 @@
 
   return;
 }
+
+// NOTE: This value should NOT be changed without renaming the histogram
+// otherwise it will create incompatible buckets.
+const int32_t
+    JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins = 5;
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+    const base::TimeDelta& commit_interval,
+    const base::FilePath& path)
+    : WriteCountHistogram(commit_interval,
+                          path,
+                          scoped_ptr<base::Clock>(new base::DefaultClock)) {
+}
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+    const base::TimeDelta& commit_interval,
+    const base::FilePath& path,
+    scoped_ptr<base::Clock> clock)
+    : commit_interval_(commit_interval),
+      path_(path),
+      clock_(clock.release()),
+      report_interval_(
+          base::TimeDelta::FromMinutes(kHistogramWriteReportIntervalMins)),
+      last_report_time_(clock_->Now()),
+      writes_since_last_report_(0) {
+}
+
+JsonPrefStore::WriteCountHistogram::~WriteCountHistogram() {
+  ReportOutstandingWrites();
+}
+
+void JsonPrefStore::WriteCountHistogram::RecordWriteOccured() {
+  ReportOutstandingWrites();
+
+  ++writes_since_last_report_;
+}
+
+void JsonPrefStore::WriteCountHistogram::ReportOutstandingWrites() {
+  base::Time current_time = clock_->Now();
+  base::TimeDelta time_since_last_report = current_time - last_report_time_;
+
+  if (time_since_last_report <= report_interval_)
+    return;
+
+  // If the time since the last report exceeds the report interval, report all
+  // the writes since the last report. They must have all occurred in the same
+  // report interval.
+  base::HistogramBase* histogram = GetHistogram();
+  histogram->Add(writes_since_last_report_);
+
+  // There may be several report intervals that elapsed that don't have any
+  // writes in them. Report these too.
+  int64 total_num_intervals_elapsed =
+      (time_since_last_report / report_interval_);
+  for (int64 i = 0; i < total_num_intervals_elapsed - 1; ++i)
+    histogram->Add(0);
+
+  writes_since_last_report_ = 0;
+  last_report_time_ += total_num_intervals_elapsed * report_interval_;
+}
+
+base::HistogramBase* JsonPrefStore::WriteCountHistogram::GetHistogram() {
+  std::string spaceless_basename;
+  base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
+                     &spaceless_basename);
+  std::string histogram_name =
+      "Settings.JsonDataWriteCount." + spaceless_basename;
+
+  // The min value for a histogram is 1. The max value is the maximum number of
+  // writes that can occur in the window being recorded. The number of buckets
+  // used is the max value (plus the underflow/overflow buckets).
+  int32_t min_value = 1;
+  int32_t max_value = report_interval_ / commit_interval_;
+  int32_t num_buckets = max_value + 1;
+
+  // NOTE: These values should NOT be changed without renaming the histogram
+  // otherwise it will create incompatible buckets.
+  DCHECK_EQ(30, max_value);
+  DCHECK_EQ(31, num_buckets);
+
+  // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+  // macro adapted to allow for a dynamically suffixed histogram name.
+  // Note: The factory creates and owns the histogram.
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      histogram_name, min_value, max_value, num_buckets,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  return histogram;
+}
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
index 16e431b..1badcf2 100644
--- a/base/prefs/json_pref_store.h
+++ b/base/prefs/json_pref_store.h
@@ -13,9 +13,10 @@
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/important_file_writer.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/observer_list.h"
 #include "base/prefs/base_prefs_export.h"
 #include "base/prefs/persistent_pref_store.h"
@@ -24,11 +25,17 @@
 class PrefFilter;
 
 namespace base {
+class Clock;
 class DictionaryValue;
 class FilePath;
+class HistogramBase;
 class SequencedTaskRunner;
 class SequencedWorkerPool;
 class Value;
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps);
 }
 
 // A writable PrefStore implementation that is used for user preferences.
@@ -98,6 +105,63 @@
       const base::Closure& on_next_successful_write);
 
  private:
+  // Represents a histogram for recording the number of writes to the pref file
+  // that occur every kHistogramWriteReportIntervalInMins minutes.
+  class BASE_PREFS_EXPORT WriteCountHistogram {
+   public:
+    static const int32_t kHistogramWriteReportIntervalMins;
+
+    WriteCountHistogram(const base::TimeDelta& commit_interval,
+                        const base::FilePath& path);
+    // Constructor for testing. |clock| is a test Clock that is used to retrieve
+    // the time.
+    WriteCountHistogram(const base::TimeDelta& commit_interval,
+                        const base::FilePath& path,
+                        scoped_ptr<base::Clock> clock);
+    ~WriteCountHistogram();
+
+    // Record that a write has occured.
+    void RecordWriteOccured();
+
+    // Reports writes (that have not yet been reported) in all of the recorded
+    // intervals that have elapsed up until current time.
+    void ReportOutstandingWrites();
+
+    base::HistogramBase* GetHistogram();
+
+   private:
+    // The minimum interval at which writes can occur.
+    const base::TimeDelta commit_interval_;
+
+    // The path to the file.
+    const base::FilePath path_;
+
+    // Clock which is used to retrieve the current time.
+    scoped_ptr<base::Clock> clock_;
+
+    // The interval at which to report write counts.
+    const base::TimeDelta report_interval_;
+
+    // The time at which the last histogram value was reported for the number
+    // of write counts.
+    base::Time last_report_time_;
+
+    // The number of writes that have occured since the last write count was
+    // reported.
+    uint32_t writes_since_last_report_;
+
+    DISALLOW_COPY_AND_ASSIGN(WriteCountHistogram);
+  };
+
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestBasic);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestSinglePeriod);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestMultiplePeriods);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestPeriodWithGaps);
+
   ~JsonPrefStore() override;
 
   // This method is called after the JSON file has been read.  It then hands
@@ -144,6 +208,8 @@
 
   std::set<std::string> keys_need_empty_value_;
 
+  WriteCountHistogram write_count_histogram_;
+
   DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
 };
 
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
index ff68836..728a57d 100644
--- a/base/prefs/json_pref_store_unittest.cc
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -7,15 +7,20 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_filter.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
@@ -27,6 +32,12 @@
 
 const char kHomePage[] = "homepage";
 
+// Set the time on the given SimpleTestClock to the given time in minutes.
+void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
+  const int32_t kBaseTimeMins = 100;
+  clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
+}
+
 // A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
 // to the |prefs| until explicitly asked to release them.
 class InterceptingPrefFilter : public PrefFilter {
@@ -97,7 +108,8 @@
   void TearDown() override {
     // Make sure all pending tasks have been processed (e.g., deleting the
     // JsonPrefStore may post write tasks).
-    message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          MessageLoop::QuitWhenIdleClosure());
     message_loop_.Run();
   }
 
@@ -107,6 +119,10 @@
   base::FilePath data_dir_;
   // A message loop that we can use as the file thread message loop.
   MessageLoop message_loop_;
+
+ private:
+  // Ensure histograms are reset for each test.
+  StatisticsRecorder statistics_recorder_;
 };
 
 // Test fallback behavior for a nonexistent file.
@@ -114,9 +130,7 @@
   base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
   ASSERT_FALSE(PathExists(bogus_input_file));
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      bogus_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+      bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
   EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
             pref_store->ReadPrefs());
   EXPECT_FALSE(pref_store->ReadOnly());
@@ -129,11 +143,9 @@
       data_dir_.AppendASCII("read_alternate.txt");
   ASSERT_FALSE(PathExists(bogus_input_file));
   ASSERT_FALSE(PathExists(bogus_alternate_input_file));
-  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      bogus_input_file,
-      bogus_alternate_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
   EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
             pref_store->ReadPrefs());
   EXPECT_FALSE(pref_store->ReadOnly());
@@ -144,10 +156,8 @@
   base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
   base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
   ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
-  scoped_refptr<JsonPrefStore> pref_store =
-      new JsonPrefStore(invalid_file,
-                        message_loop_.message_loop_proxy().get(),
-                        scoped_ptr<PrefFilter>());
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
   EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
             pref_store->ReadPrefs());
   EXPECT_FALSE(pref_store->ReadOnly());
@@ -233,9 +243,7 @@
   base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
   ASSERT_TRUE(PathExists(input_file));
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+      input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
   ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
   EXPECT_FALSE(pref_store->ReadOnly());
   EXPECT_TRUE(pref_store->IsInitializationComplete());
@@ -262,9 +270,7 @@
   base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
   ASSERT_TRUE(PathExists(input_file));
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+      input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   {
     MockPrefStoreObserver mock_observer;
@@ -301,9 +307,7 @@
   FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
 
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      pref_file,
-      message_loop_.message_loop_proxy(),
-      scoped_ptr<PrefFilter>());
+      pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   // Set some keys with empty values.
   pref_store->SetValue("list", new base::ListValue);
@@ -314,10 +318,8 @@
   MessageLoop::current()->RunUntilIdle();
 
   // Reload.
-  pref_store = new JsonPrefStore(
-      pref_file,
-      message_loop_.message_loop_proxy(),
-      scoped_ptr<PrefFilter>());
+  pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
+                                 scoped_ptr<PrefFilter>());
   ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
   ASSERT_FALSE(pref_store->ReadOnly());
 
@@ -335,9 +337,7 @@
   FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
 
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      pref_file,
-      message_loop_.message_loop_proxy(),
-      scoped_ptr<PrefFilter>());
+      pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   base::DictionaryValue* dict = new base::DictionaryValue;
   dict->SetString("key", "value");
@@ -355,9 +355,7 @@
   base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
   ASSERT_FALSE(PathExists(bogus_input_file));
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      bogus_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+      bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
   MockPrefStoreObserver mock_observer;
   pref_store->AddObserver(&mock_observer);
 
@@ -385,10 +383,8 @@
       new InterceptingPrefFilter());
   InterceptingPrefFilter* raw_intercepting_pref_filter_ =
       intercepting_pref_filter.get();
-  scoped_refptr<JsonPrefStore> pref_store =
-      new JsonPrefStore(input_file,
-                        message_loop_.message_loop_proxy().get(),
-                        intercepting_pref_filter.Pass());
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
 
   ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
             pref_store->ReadPrefs());
@@ -432,10 +428,8 @@
       new InterceptingPrefFilter());
   InterceptingPrefFilter* raw_intercepting_pref_filter_ =
       intercepting_pref_filter.get();
-  scoped_refptr<JsonPrefStore> pref_store =
-      new JsonPrefStore(input_file,
-                        message_loop_.message_loop_proxy().get(),
-                        intercepting_pref_filter.Pass());
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
 
   MockPrefStoreObserver mock_observer;
   pref_store->AddObserver(&mock_observer);
@@ -498,11 +492,9 @@
       temp_dir_.path().AppendASCII("alternate.json");
   ASSERT_FALSE(PathExists(input_file));
   ASSERT_TRUE(PathExists(alternate_input_file));
-  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      input_file,
-      alternate_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   ASSERT_FALSE(PathExists(input_file));
   ASSERT_TRUE(PathExists(alternate_input_file));
@@ -544,11 +536,9 @@
       temp_dir_.path().AppendASCII("alternate.json");
   ASSERT_TRUE(PathExists(input_file));
   ASSERT_TRUE(PathExists(alternate_input_file));
-  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      input_file,
-      alternate_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   ASSERT_TRUE(PathExists(input_file));
   ASSERT_TRUE(PathExists(alternate_input_file));
@@ -586,11 +576,9 @@
       temp_dir_.path().AppendASCII("alternate.json");
   ASSERT_TRUE(PathExists(input_file));
   ASSERT_FALSE(PathExists(alternate_input_file));
-  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      input_file,
-      alternate_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   ASSERT_TRUE(PathExists(input_file));
   ASSERT_FALSE(PathExists(alternate_input_file));
@@ -628,11 +616,9 @@
       temp_dir_.path().AppendASCII("alternate.json");
   ASSERT_FALSE(PathExists(input_file));
   ASSERT_TRUE(PathExists(alternate_input_file));
-  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
-      input_file,
-      alternate_input_file,
-      message_loop_.message_loop_proxy().get(),
-      scoped_ptr<PrefFilter>());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   ASSERT_FALSE(PathExists(input_file));
   ASSERT_TRUE(PathExists(alternate_input_file));
@@ -671,4 +657,148 @@
       pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
 }
 
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(1));
+  ASSERT_EQ(1, samples->TotalCount());
+
+  ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
+            histogram.GetHistogram()->histogram_name());
+  ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // Nothing should be recorded until the report period has elapsed.
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(0, samples->TotalCount());
+
+  SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // Now the report period has elapsed.
+  samples = histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(1, samples->TotalCount());
+
+  // The last write won't be recorded because the second count period hasn't
+  // fully elapsed.
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+
+  samples = histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // The last write won't be recorded because the second count period hasn't
+  // fully elapsed
+  SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(2, samples->GetCount(3));
+  ASSERT_EQ(1, samples->GetCount(2));
+  ASSERT_EQ(3, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  // 1 write in the first period.
+  histogram.RecordWriteOccured();
+
+  // No writes in the second and third periods.
+
+  // 2 writes in the fourth period.
+  SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // No writes in the fifth period.
+
+  // 3 writes in the sixth period.
+  SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(3, samples->GetCount(0));
+  ASSERT_EQ(1, samples->GetCount(1));
+  ASSERT_EQ(1, samples->GetCount(2));
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(6, samples->TotalCount());
+}
+
 }  // namespace base
diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc
index 8d80dd0..64c3d6a 100644
--- a/base/prefs/pref_member.cc
+++ b/base/prefs/pref_member.cc
@@ -7,11 +7,10 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/prefs/pref_service.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/value_conversions.h"
 
-using base::MessageLoopProxy;
 using base::SingleThreadTaskRunner;
 
 namespace subtle {
@@ -52,12 +51,12 @@
 }
 
 void PrefMemberBase::MoveToThread(
-    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
   VerifyValuePrefName();
   // Load the value from preferences if it hasn't been loaded so far.
   if (!internal())
     UpdateValueFromPref(base::Closure());
-  internal()->MoveToThread(task_runner);
+  internal()->MoveToThread(task_runner.Pass());
 }
 
 void PrefMemberBase::OnPreferenceChanged(PrefService* service,
@@ -91,15 +90,14 @@
 }
 
 PrefMemberBase::Internal::Internal()
-    : thread_loop_(MessageLoopProxy::current()),
+    : thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       is_managed_(false),
       is_user_modifiable_(false) {
 }
 PrefMemberBase::Internal::~Internal() { }
 
 bool PrefMemberBase::Internal::IsOnCorrectThread() const {
-  // In unit tests, there may not be a message loop.
-  return thread_loop_.get() == NULL || thread_loop_->BelongsToCurrentThread();
+  return thread_task_runner_->BelongsToCurrentThread();
 }
 
 void PrefMemberBase::Internal::UpdateValue(
@@ -115,19 +113,18 @@
     is_managed_ = is_managed;
     is_user_modifiable_ = is_user_modifiable;
   } else {
-    bool may_run = thread_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
-                   value.release(), is_managed, is_user_modifiable,
-                   closure_runner.Release()));
+    bool may_run = thread_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
+                              value.release(), is_managed, is_user_modifiable,
+                              closure_runner.Release()));
     DCHECK(may_run);
   }
 }
 
 void PrefMemberBase::Internal::MoveToThread(
-    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
   CheckOnCorrectThread();
-  thread_loop_ = task_runner;
+  thread_task_runner_ = task_runner.Pass();
 }
 
 bool PrefMemberVectorStringUpdate(const base::Value& value,
diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h
index 9b140d1..6dceb43 100644
--- a/base/prefs/pref_member.h
+++ b/base/prefs/pref_member.h
@@ -65,8 +65,7 @@
                      bool is_user_modifiable,
                      const base::Closure& callback) const;
 
-    void MoveToThread(
-        const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+    void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
     // See PrefMember<> for description.
     bool IsManaged() const {
@@ -92,7 +91,7 @@
 
     bool IsOnCorrectThread() const;
 
-    scoped_refptr<base::SingleThreadTaskRunner> thread_loop_;
+    scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
     mutable bool is_managed_;
     mutable bool is_user_modifiable_;
 
@@ -113,8 +112,7 @@
   // See PrefMember<> for description.
   void Destroy();
 
-  void MoveToThread(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+  void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // PrefObserver
   void OnPreferenceChanged(PrefService* service,
@@ -201,8 +199,7 @@
   // via PostTask.
   // This method should only be used from the thread the PrefMember is currently
   // on, which is the UI thread by default.
-  void MoveToThread(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+  void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
     subtle::PrefMemberBase::MoveToThread(task_runner);
   }
 
diff --git a/base/prefs/pref_member_unittest.cc b/base/prefs/pref_member_unittest.cc
index 435122b..a776e2c 100644
--- a/base/prefs/pref_member_unittest.cc
+++ b/base/prefs/pref_member_unittest.cc
@@ -5,9 +5,10 @@
 #include "base/prefs/pref_member.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/testing_pref_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +38,7 @@
 
   void Init(const std::string& pref_name, PrefService* prefs) {
     pref_.Init(pref_name, prefs);
-    pref_.MoveToThread(pref_thread_.message_loop_proxy());
+    pref_.MoveToThread(pref_thread_.task_runner());
   }
 
   void Destroy() {
@@ -46,10 +47,9 @@
 
   void FetchValue() {
     base::WaitableEvent event(true, false);
-    ASSERT_TRUE(
-        pref_thread_.message_loop_proxy()->PostTask(
-            FROM_HERE,
-            base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
+    ASSERT_TRUE(pref_thread_.task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
     event.Wait();
   }
 
@@ -100,7 +100,11 @@
 
 }  // anonymous namespace
 
-TEST(PrefMemberTest, BasicGetAndSet) {
+class PrefMemberTest : public testing::Test {
+  base::MessageLoop message_loop_;
+};
+
+TEST_F(PrefMemberTest, BasicGetAndSet) {
   TestingPrefServiceSimple prefs;
   RegisterTestPrefs(prefs.registry());
 
@@ -227,7 +231,7 @@
   EXPECT_EQ(expected_vector, *string_list);
 }
 
-TEST(PrefMemberTest, InvalidList) {
+TEST_F(PrefMemberTest, InvalidList) {
   // Set the vector to an initial good value.
   std::vector<std::string> expected_vector;
   expected_vector.push_back("foo");
@@ -245,7 +249,7 @@
   EXPECT_EQ(expected_vector, vector);
 }
 
-TEST(PrefMemberTest, TwoPrefs) {
+TEST_F(PrefMemberTest, TwoPrefs) {
   // Make sure two DoublePrefMembers stay in sync.
   TestingPrefServiceSimple prefs;
   RegisterTestPrefs(prefs.registry());
@@ -266,7 +270,7 @@
   EXPECT_EQ(4.2, *pref2);
 }
 
-TEST(PrefMemberTest, Observer) {
+TEST_F(PrefMemberTest, Observer) {
   TestingPrefServiceSimple prefs;
   RegisterTestPrefs(prefs.registry());
 
@@ -293,12 +297,12 @@
   EXPECT_EQ("hello", prefs.GetString(kStringPref));
 }
 
-TEST(PrefMemberTest, NoInit) {
+TEST_F(PrefMemberTest, NoInit) {
   // Make sure not calling Init on a PrefMember doesn't cause problems.
   IntegerPrefMember pref;
 }
 
-TEST(PrefMemberTest, MoveToThread) {
+TEST_F(PrefMemberTest, MoveToThread) {
   TestingPrefServiceSimple prefs;
   scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper());
   RegisterTestPrefs(prefs.registry());
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc
index 5afb5ea..3ccdae7 100644
--- a/base/prefs/pref_service.cc
+++ b/base/prefs/pref_service.cc
@@ -8,16 +8,18 @@
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/default_pref_store.h"
 #include "base/prefs/pref_notifier_impl.h"
 #include "base/prefs/pref_registry.h"
 #include "base/prefs/pref_value_store.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/value_conversions.h"
 #include "build/build_config.h"
 
@@ -79,10 +81,9 @@
     read_error_callback_.Run(user_pref_store_->ReadPrefs());
   } else {
     // Guarantee that initialization happens after this function returned.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&PersistentPrefStore::ReadPrefsAsync,
-                   user_pref_store_.get(),
+        base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_.get(),
                    new ReadErrorHandler(read_error_callback_)));
   }
 }
diff --git a/base/prefs/pref_service_factory.cc b/base/prefs/pref_service_factory.cc
index d644cb1..8caf073 100644
--- a/base/prefs/pref_service_factory.cc
+++ b/base/prefs/pref_service_factory.cc
@@ -10,8 +10,8 @@
 #include "base/prefs/pref_filter.h"
 #include "base/prefs/pref_notifier_impl.h"
 #include "base/prefs/pref_service.h"
-
 #include "base/prefs/pref_value_store.h"
+#include "base/sequenced_task_runner.h"
 
 namespace base {
 
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
index ed7d7f4..d2e9ec5 100644
--- a/base/process/internal_linux.cc
+++ b/base/process/internal_linux.cc
@@ -106,12 +106,10 @@
 
 typedef std::map<std::string, std::string> ProcStatMap;
 void ParseProcStat(const std::string& contents, ProcStatMap* output) {
-  typedef std::pair<std::string, std::string> StringPair;
-  std::vector<StringPair> key_value_pairs;
+  base::StringPairs key_value_pairs;
   SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
   for (size_t i = 0; i < key_value_pairs.size(); ++i) {
-    const StringPair& key_value_pair = key_value_pairs[i];
-    output->insert(key_value_pair);
+    output->insert(key_value_pairs[i]);
   }
 }
 
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
index 4f8bc2d..f06a8c6 100644
--- a/base/profiler/scoped_profile.cc
+++ b/base/profiler/scoped_profile.cc
@@ -20,7 +20,6 @@
   if (!birth_)
     return;
 
-  ThreadData::PrepareForStartOfRun(birth_);
   stopwatch_.Start();
 }
 
diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc
index 3fa9383..4806a90 100644
--- a/base/profiler/tracked_time_unittest.cc
+++ b/base/profiler/tracked_time_unittest.cc
@@ -78,8 +78,7 @@
 }
 
 TEST(TrackedTimeTest, TrackedTimerEnabled) {
-  if (!ThreadData::InitializeAndSetTrackingStatus(
-      ThreadData::PROFILING_CHILDREN_ACTIVE))
+  if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE))
     return;
   // Make sure that when we enable tracking, we get a real timer result.
 
diff --git a/base/scoped_observer.h b/base/scoped_observer.h
index 5b0d533..422701b 100644
--- a/base/scoped_observer.h
+++ b/base/scoped_observer.h
@@ -48,6 +48,8 @@
         sources_.end();
   }
 
+  bool IsObservingSources() const { return !sources_.empty(); }
+
  private:
   Observer* observer_;
 
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
index 9aae82c..0aa0f9c 100644
--- a/base/sequence_checker_unittest.cc
+++ b/base/sequence_checker_unittest.cc
@@ -9,8 +9,8 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/test/sequenced_worker_pool_owner.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -84,10 +84,9 @@
 
   void PostDoStuffToOtherThread(
       SequenceCheckedObject* sequence_checked_object) {
-    other_thread()->message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&SequenceCheckedObject::DoStuff,
-                   base::Unretained(sequence_checked_object)));
+    other_thread()->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&SequenceCheckedObject::DoStuff,
+                              base::Unretained(sequence_checked_object)));
   }
 
   void PostDeleteToOtherThread(
diff --git a/base/single_thread_task_runner.h b/base/single_thread_task_runner.h
index b5311db..6e93193 100644
--- a/base/single_thread_task_runner.h
+++ b/base/single_thread_task_runner.h
@@ -16,7 +16,8 @@
 // there is a specific need to run tasks on only a single thread.
 //
 // SingleThreadTaskRunner implementations might:
-//   - Post tasks to an existing thread's MessageLoop (see MessageLoopProxy).
+//   - Post tasks to an existing thread's MessageLoop (see
+//     MessageLoop::task_runner()).
 //   - Create their own worker thread and MessageLoop to post tasks to.
 //   - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
 //     be processed. This allows TaskRunner-oriented code run on threads
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index e084cb5..6f6d6e2 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -454,8 +454,6 @@
   return DoLowerCaseEqualsASCII(a_begin, a_end, b);
 }
 
-// TODO(port): Resolve wchar_t/iterator issues that require OS_ANDROID here.
-#if !defined(OS_ANDROID)
 bool LowerCaseEqualsASCII(const char* a_begin,
                           const char* a_end,
                           const char* b) {
@@ -468,8 +466,6 @@
   return DoLowerCaseEqualsASCII(a_begin, a_end, b);
 }
 
-#endif  // !defined(OS_ANDROID)
-
 bool EqualsASCII(const string16& a, const base::StringPiece& b) {
   if (a.length() != b.length())
     return false;
diff --git a/base/synchronization/cancellation_flag_unittest.cc b/base/synchronization/cancellation_flag_unittest.cc
index 02b08b6..13c74bc 100644
--- a/base/synchronization/cancellation_flag_unittest.cc
+++ b/base/synchronization/cancellation_flag_unittest.cc
@@ -7,8 +7,9 @@
 #include "base/synchronization/cancellation_flag.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/spin_wait.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
@@ -56,7 +57,7 @@
   ASSERT_TRUE(t.IsRunning());
 
   CancellationFlag flag;
-  t.message_loop()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
+  t.task_runner()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
 }
 
 }  // namespace
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
index 5d7a0ab..e63a723 100644
--- a/base/synchronization/condition_variable_unittest.cc
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -9,8 +9,10 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/spin_wait.h"
@@ -220,7 +222,7 @@
 
   Thread thread("Helper");
   thread.Start();
-  thread.message_loop()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
+  thread.task_runner()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
 
   TimeTicks start = TimeTicks::Now();
   const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300);
diff --git a/base/synchronization/waitable_event_watcher_posix.cc b/base/synchronization/waitable_event_watcher_posix.cc
index 6fc337c..ad66a4c 100644
--- a/base/synchronization/waitable_event_watcher_posix.cc
+++ b/base/synchronization/waitable_event_watcher_posix.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 
@@ -68,7 +68,7 @@
   bool Fire(WaitableEvent* event) override {
     // Post the callback if we haven't been cancelled.
     if (!flag_->value()) {
-      message_loop_->PostTask(FROM_HERE, callback_);
+      message_loop_->task_runner()->PostTask(FROM_HERE, callback_);
     }
 
     // We are removed from the wait-list by the WaitableEvent itself. It only
@@ -158,7 +158,7 @@
 
     // No hairpinning - we can't call the delegate directly here. We have to
     // enqueue a task on the MessageLoop as normal.
-    current_ml->PostTask(FROM_HERE, internal_callback_);
+    current_ml->task_runner()->PostTask(FROM_HERE, internal_callback_);
     return true;
   }
 
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index ef5f1fe..9915055 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -109,7 +109,7 @@
     // Parse and cache lsb_release key pairs. There should only be a handful
     // of entries so the overhead for this will be small, and it can be
     // useful for debugging.
-    std::vector<std::pair<std::string, std::string> > pairs;
+    base::StringPairs pairs;
     SplitStringIntoKeyValuePairs(lsb_release, '=', '\n', &pairs);
     for (size_t i = 0; i < pairs.size(); ++i) {
       std::string key, value;
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc
index b6e4b6a..a2e4799 100644
--- a/base/task/cancelable_task_tracker.cc
+++ b/base/task/cancelable_task_tracker.cc
@@ -11,9 +11,10 @@
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/cancellation_flag.h"
 #include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 using base::Bind;
 using base::CancellationFlag;
@@ -85,7 +86,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // We need a MessageLoop to run reply.
-  DCHECK(base::MessageLoopProxy::current().get());
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
 
   // Owned by reply callback below.
   CancellationFlag* flag = new CancellationFlag();
@@ -113,7 +114,7 @@
 CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
     IsCanceledCallback* is_canceled_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(base::MessageLoopProxy::current().get());
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
 
   TaskId id = next_id_;
   next_id_++;  // int64 is big enough that we ignore the potential overflow.
@@ -129,7 +130,7 @@
   // Will always run |untrack_and_delete_flag| on current MessageLoop.
   base::ScopedClosureRunner* untrack_and_delete_flag_runner =
       new base::ScopedClosureRunner(Bind(&RunOrPostToTaskRunner,
-                                         base::MessageLoopProxy::current(),
+                                         base::ThreadTaskRunnerHandle::Get(),
                                          untrack_and_delete_flag));
 
   *is_canceled_cb =
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc
index 8b2b86a..ff9e40b 100644
--- a/base/task/cancelable_task_tracker_unittest.cc
+++ b/base/task/cancelable_task_tracker_unittest.cc
@@ -13,8 +13,8 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -84,15 +84,13 @@
   Thread worker_thread("worker thread");
   ASSERT_TRUE(worker_thread.Start());
 
-  ignore_result(task_tracker_.PostTask(worker_thread.message_loop_proxy().get(),
+  ignore_result(task_tracker_.PostTask(worker_thread.task_runner().get(),
                                        FROM_HERE,
                                        MakeExpectedRunClosure(FROM_HERE)));
 
-  ignore_result(
-      task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
-                                     FROM_HERE,
-                                     MakeExpectedRunClosure(FROM_HERE),
-                                     MakeExpectedRunClosure(FROM_HERE)));
+  ignore_result(task_tracker_.PostTaskAndReply(
+      worker_thread.task_runner().get(), FROM_HERE,
+      MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE)));
 
   CancelableTaskTracker::IsCanceledCallback is_canceled;
   ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
@@ -166,11 +164,9 @@
   Thread worker_thread("worker thread");
   ASSERT_TRUE(worker_thread.Start());
 
-  CancelableTaskTracker::TaskId task_id =
-      task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
-                                     FROM_HERE,
-                                     Bind(&DoNothing),
-                                     MakeExpectedNotRunClosure(FROM_HERE));
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply(
+      worker_thread.task_runner().get(), FROM_HERE, Bind(&DoNothing),
+      MakeExpectedNotRunClosure(FROM_HERE));
   EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
 
   task_tracker_.TryCancel(task_id);
@@ -196,14 +192,14 @@
 
   Thread other_thread("other thread");
   ASSERT_TRUE(other_thread.Start());
-  other_thread.message_loop_proxy()->PostTask(
+  other_thread.task_runner()->PostTask(
       FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, false));
   other_thread.Stop();
 
   task_tracker_.TryCancel(task_id);
 
   ASSERT_TRUE(other_thread.Start());
-  other_thread.message_loop_proxy()->PostTask(
+  other_thread.task_runner()->PostTask(
       FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, true));
   other_thread.Stop();
 }
@@ -378,11 +374,9 @@
   Thread bad_thread("bad thread");
   ASSERT_TRUE(bad_thread.Start());
 
-  bad_thread.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
-           Unretained(&task_tracker_),
-           Bind(&PostDoNothingTask)));
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+                      Unretained(&task_tracker_), Bind(&PostDoNothingTask)));
 }
 
 void TryCancel(CancelableTaskTracker::TaskId task_id,
@@ -401,11 +395,9 @@
       test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
   EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
 
-  bad_thread.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
-           Unretained(&task_tracker_),
-           Bind(&TryCancel, task_id)));
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+                      Unretained(&task_tracker_), Bind(&TryCancel, task_id)));
 
   test_task_runner->RunUntilIdle();
 }
@@ -421,10 +413,9 @@
       test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
   EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
 
-  bad_thread.message_loop_proxy()->PostTask(
+  bad_thread.task_runner()->PostTask(
       FROM_HERE,
-      Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
-           Unretained(&task_tracker_),
+      Bind(&MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_),
            Bind(&CancelableTaskTracker::TryCancelAll)));
 
   test_task_runner->RunUntilIdle();
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index 481f09e..8245cfc 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/task_runner_util.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -69,8 +69,7 @@
   int result = 0;
 
   MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
-                             FROM_HERE,
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
                              Bind(&ReturnFourtyTwo),
                              Bind(&StoreValue, &result));
 
@@ -83,8 +82,7 @@
   double result = 0;
 
   MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
-                             FROM_HERE,
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
                              Bind(&ReturnFourtyTwo),
                              Bind(&StoreDoubleValue, &result));
 
@@ -98,10 +96,8 @@
   g_foo_free_count = 0;
 
   MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
-                             FROM_HERE,
-                             Bind(&CreateFoo),
-                             Bind(&ExpectFoo));
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&CreateFoo), Bind(&ExpectFoo));
 
   RunLoop().RunUntilIdle();
 
@@ -114,10 +110,8 @@
   g_foo_free_count = 0;
 
   MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
-                             FROM_HERE,
-                             Bind(&CreateScopedFoo),
-                             Bind(&ExpectScopedFoo));
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo));
 
   RunLoop().RunUntilIdle();
 
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 a104831..8a3395a 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
@@ -14,10 +14,12 @@
 import junit.framework.TestResult;
 
 import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.test.reporter.TestStatusListener;
 
 import java.util.ArrayList;
 import java.util.List;
 
+// TODO(jbudorick): Add support for on-device handling of timeouts.
 /**
  *  An Instrumentation test runner that checks SDK level for tests with specific requirements.
  */
@@ -88,7 +90,7 @@
 
     @Override
     protected AndroidTestRunner getAndroidTestRunner() {
-        return new AndroidTestRunner() {
+        AndroidTestRunner runner = new AndroidTestRunner() {
             @Override
             protected TestResult createTestResult() {
                 SkippingTestResult r = new SkippingTestResult();
@@ -96,6 +98,8 @@
                 return r;
             }
         };
+        runner.addTestListener(new TestStatusListener(getContext()));
+        return runner;
     }
 
     /**
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 521f69c..7f258f5 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -18,11 +18,13 @@
 #include "base/format_macros.h"
 #include "base/hash.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/process/kill.h"
 #include "base/process/launch.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"
@@ -34,6 +36,7 @@
 #include "base/test/sequenced_worker_pool_owner.h"
 #include "base/test/test_switches.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -349,7 +352,7 @@
     TimeDelta timeout,
     int flags,
     bool redirect_stdio,
-    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    SingleThreadTaskRunner* task_runner,
     const TestLauncher::LaunchChildGTestProcessCallback& callback) {
   TimeTicks start_time = TimeTicks::Now();
 
@@ -423,14 +426,9 @@
 
   // Run target callback on the thread it was originating from, not on
   // a worker pool thread.
-  message_loop_proxy->PostTask(
-      FROM_HERE,
-      Bind(&RunCallback,
-           callback,
-           exit_code,
-           TimeTicks::Now() - start_time,
-           was_timeout,
-           output_file_contents));
+  task_runner->PostTask(FROM_HERE, Bind(&RunCallback, callback, exit_code,
+                                        TimeTicks::Now() - start_time,
+                                        was_timeout, output_file_contents));
 }
 
 }  // namespace
@@ -504,9 +502,8 @@
   // Start the watchdog timer.
   watchdog_timer_.Reset();
 
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
 
   MessageLoop::current()->Run();
 
@@ -536,16 +533,10 @@
   bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled();
 
   worker_pool_owner_->pool()->PostWorkerTask(
-      FROM_HERE,
-      Bind(&DoLaunchChildTestProcess,
-           new_command_line,
-           timeout,
-           flags,
-           redirect_stdio,
-           MessageLoopProxy::current(),
-           Bind(&TestLauncher::OnLaunchTestProcessFinished,
-                Unretained(this),
-                callback)));
+      FROM_HERE, Bind(&DoLaunchChildTestProcess, new_command_line, timeout,
+                      flags, redirect_stdio, ThreadTaskRunnerHandle::Get(),
+                      Bind(&TestLauncher::OnLaunchTestProcessFinished,
+                           Unretained(this), callback)));
 }
 
 void TestLauncher::OnTestFinished(const TestResult& result) {
@@ -957,9 +948,8 @@
     fflush(stdout);
 
     // No tests have actually been started, so kick off the next iteration.
-    MessageLoop::current()->PostTask(
-        FROM_HERE,
-        Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+    ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
   }
 }
 
@@ -980,7 +970,7 @@
   tests_to_retry_.clear();
   results_tracker_.OnTestIterationStarting();
 
-  MessageLoop::current()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, Bind(&TestLauncher::RunTests, Unretained(this)));
 }
 
@@ -1027,9 +1017,8 @@
   results_tracker_.PrintSummaryOfCurrentIteration();
 
   // Kick off the next iteration.
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
 }
 
 void TestLauncher::OnOutputTimeout() {
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 1b3a162..ab6fa72 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -12,7 +12,9 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -22,6 +24,7 @@
 #include "base/test/test_switches.h"
 #include "base/test/test_timeouts.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -405,13 +408,10 @@
   // The temporary file's directory is also temporary.
   DeleteFile(callback_state.output_file.DirName(), true);
 
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      Bind(&RunUnitTestsSerially,
-           callback_state.test_launcher,
-           callback_state.platform_delegate,
-           test_names,
-           callback_state.launch_flags));
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&RunUnitTestsSerially, callback_state.test_launcher,
+                      callback_state.platform_delegate, test_names,
+                      callback_state.launch_flags));
 }
 
 }  // namespace
@@ -576,12 +576,9 @@
 size_t UnitTestLauncherDelegate::RetryTests(
     TestLauncher* test_launcher,
     const std::vector<std::string>& test_names) {
-  MessageLoop::current()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      Bind(&RunUnitTestsSerially,
-           test_launcher,
-           platform_delegate_,
-           test_names,
+      Bind(&RunUnitTestsSerially, test_launcher, platform_delegate_, test_names,
            use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0));
   return test_names.size();
 }
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc
index 4486323..b0d8b7a 100644
--- a/base/test/sequenced_worker_pool_owner.cc
+++ b/base/test/sequenced_worker_pool_owner.cc
@@ -6,6 +6,7 @@
 
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 
 namespace base {
 
@@ -50,9 +51,8 @@
 }
 
 void SequencedWorkerPoolOwner::OnDestruct() {
-  constructor_message_loop_->PostTask(
-      FROM_HERE,
-      constructor_message_loop_->QuitWhenIdleClosure());
+  constructor_message_loop_->task_runner()->PostTask(
+      FROM_HERE, constructor_message_loop_->QuitWhenIdleClosure());
 }
 
 }  // namespace base
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
index 9bcf70b..ee2b876 100644
--- a/base/test/task_runner_test_template.h
+++ b/base/test/task_runner_test_template.h
@@ -53,7 +53,9 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/task_runner.h"
@@ -195,7 +197,7 @@
             i);
     for (int j = 0; j < i + 1; ++j) {
       task_runner->PostTask(FROM_HERE, ith_task_runner_task);
-      thread.message_loop()->PostTask(FROM_HERE, ith_non_task_runner_task);
+      thread.task_runner()->PostTask(FROM_HERE, ith_non_task_runner_task);
       expected_task_run_counts[i] += 2;
     }
   }
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index ee135e5..6c766eb 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -51,6 +51,8 @@
 #include "base/test/test_support_ios.h"
 #endif
 
+namespace base {
+
 namespace {
 
 class MaybeTestDisabler : public testing::EmptyTestEventListener {
@@ -66,35 +68,31 @@
 class TestClientInitializer : public testing::EmptyTestEventListener {
  public:
   TestClientInitializer()
-      : old_command_line_(base::CommandLine::NO_PROGRAM) {
+      : old_command_line_(CommandLine::NO_PROGRAM) {
   }
 
   void OnTestStart(const testing::TestInfo& test_info) override {
-    old_command_line_ = *base::CommandLine::ForCurrentProcess();
+    old_command_line_ = *CommandLine::ForCurrentProcess();
   }
 
   void OnTestEnd(const testing::TestInfo& test_info) override {
-    *base::CommandLine::ForCurrentProcess() = old_command_line_;
+    *CommandLine::ForCurrentProcess() = old_command_line_;
   }
 
  private:
-  base::CommandLine old_command_line_;
+  CommandLine old_command_line_;
 
   DISALLOW_COPY_AND_ASSIGN(TestClientInitializer);
 };
 
 }  // namespace
 
-namespace base {
-
 int RunUnitTestsUsingBaseTestSuite(int argc, char **argv) {
   TestSuite test_suite(argc, argv);
-  return base::LaunchUnitTests(
-      argc, argv, Bind(&TestSuite::Run, Unretained(&test_suite)));
+  return LaunchUnitTests(argc, argv,
+                         Bind(&TestSuite::Run, Unretained(&test_suite)));
 }
 
-}  // namespace base
-
 TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) {
   PreInitialize(true);
   InitializeFromCommandLine(argc, argv);
@@ -116,11 +114,11 @@
 
 TestSuite::~TestSuite() {
   if (initialized_command_line_)
-    base::CommandLine::Reset();
+    CommandLine::Reset();
 }
 
 void TestSuite::InitializeFromCommandLine(int argc, char** argv) {
-  initialized_command_line_ = base::CommandLine::Init(argc, argv);
+  initialized_command_line_ = CommandLine::Init(argc, argv);
   testing::InitGoogleTest(&argc, argv);
   testing::InitGoogleMock(&argc, argv);
 
@@ -132,7 +130,7 @@
 #if defined(OS_WIN)
 void TestSuite::InitializeFromCommandLine(int argc, wchar_t** argv) {
   // Windows CommandLine::Init ignores argv anyway.
-  initialized_command_line_ = base::CommandLine::Init(argc, NULL);
+  initialized_command_line_ = CommandLine::Init(argc, NULL);
   testing::InitGoogleTest(&argc, argv);
   testing::InitGoogleMock(&argc, argv);
 }
@@ -142,7 +140,7 @@
 #if defined(OS_WIN)
   testing::GTEST_FLAG(catch_exceptions) = false;
 #endif
-  base::EnableTerminationOnHeapCorruption();
+  EnableTerminationOnHeapCorruption();
 #if defined(OS_LINUX) && defined(USE_AURA)
   // When calling native char conversion functions (e.g wrctomb) we need to
   // have the locale set. In the absence of such a call the "C" locale is the
@@ -154,7 +152,7 @@
   // testing/android/native_test_wrapper.cc before main() is called.
 #if !defined(OS_ANDROID)
   if (create_at_exit_manager)
-    at_exit_manager_.reset(new base::AtExitManager);
+    at_exit_manager_.reset(new AtExitManager);
 #endif
 
   // Don't add additional code to this function.  Instead add it to
@@ -181,13 +179,13 @@
 
 void TestSuite::AddTestLauncherResultPrinter() {
   // Only add the custom printer if requested.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kTestLauncherOutput)) {
     return;
   }
 
-  FilePath output_path(base::CommandLine::ForCurrentProcess()->
-                           GetSwitchValuePath(switches::kTestLauncherOutput));
+  FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+      switches::kTestLauncherOutput));
 
   // Do not add the result printer if output path already exists. It's an
   // indicator there is a process printing to that file, and we're likely
@@ -213,19 +211,19 @@
 #endif
 
 #if defined(OS_MACOSX)
-  base::mac::ScopedNSAutoreleasePool scoped_pool;
+  mac::ScopedNSAutoreleasePool scoped_pool;
 #endif
 
   Initialize();
   std::string client_func =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kTestChildProcess);
 
   // Check to see if we are being run as a client process.
   if (!client_func.empty())
     return multi_process_function_list::InvokeChildProcessTest(client_func);
 #if defined(OS_IOS)
-  base::test_listener_ios::RegisterTestEndListener();
+  test_listener_ios::RegisterTestEndListener();
 #endif
   int result = RUN_ALL_TESTS();
 
@@ -285,9 +283,8 @@
 
 void TestSuite::Initialize() {
 #if !defined(OS_IOS)
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kWaitForDebugger)) {
-    base::debug::WaitForDebugger(60, true);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWaitForDebugger)) {
+    debug::WaitForDebugger(60, true);
   }
 #endif
 
@@ -299,9 +296,9 @@
   InitAndroidTest();
 #else
   // Initialize logging.
-  base::FilePath exe;
-  PathService::Get(base::FILE_EXE, &exe);
-  base::FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+  FilePath exe;
+  PathService::Get(FILE_EXE, &exe);
+  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
   logging::LoggingSettings settings;
   settings.logging_dest = logging::LOG_TO_ALL;
   settings.log_file = log_filename.value().c_str();
@@ -312,23 +309,22 @@
   logging::SetLogItems(true, true, true, true);
 #endif  // else defined(OS_ANDROID)
 
-  CHECK(base::debug::EnableInProcessStackDumping());
+  CHECK(debug::EnableInProcessStackDumping());
 #if defined(OS_WIN)
   // Make sure we run with high resolution timer to minimize differences
   // between production code and test code.
-  base::Time::EnableHighResolutionTimer(true);
+  Time::EnableHighResolutionTimer(true);
 #endif  // defined(OS_WIN)
 
   // In some cases, we do not want to see standard error dialogs.
-  if (!base::debug::BeingDebugged() &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          "show-error-dialogs")) {
+  if (!debug::BeingDebugged() &&
+      !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
     SuppressErrorDialogs();
-    base::debug::SetSuppressDebugUI(true);
+    debug::SetSuppressDebugUI(true);
     logging::SetLogAssertHandler(UnitTestAssertHandler);
   }
 
-  base::i18n::InitializeICU();
+  i18n::InitializeICU();
   // On the Mac OS X command line, the default locale is *_POSIX. In Chromium,
   // the locale is set via an OS X locale API and is never *_POSIX.
   // Some tests (such as those involving word break iterator) will behave
@@ -338,11 +334,11 @@
   // TODO(jshin): Should we set the locale via an OS X locale API here?
 #if !defined(OS_WIN)
 #if defined(OS_IOS)
-  base::i18n::SetICUDefaultLocale("en_US");
+  i18n::SetICUDefaultLocale("en_US");
 #else
   std::string default_locale(uloc_getDefault());
   if (EndsWith(default_locale, "POSIX", false))
-    base::i18n::SetICUDefaultLocale("en_US");
+    i18n::SetICUDefaultLocale("en_US");
 #endif
 #endif
 
@@ -357,3 +353,5 @@
 
 void TestSuite::Shutdown() {
 }
+
+}  // namespace base
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
index fa0ab6c..cf0dd3a 100644
--- a/base/test/test_suite.h
+++ b/base/test/test_suite.h
@@ -90,8 +90,4 @@
 
 }  // namespace base
 
-// TODO(brettw) remove this. This is a temporary hack to allow WebKit to compile
-// until we can update it to use "base::" (preventing a two-sided patch).
-using base::TestSuite;
-
 #endif  // BASE_TEST_TEST_SUITE_H_
diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc
index 2bd3ba5..6a12190 100644
--- a/base/test/thread_test_helper.cc
+++ b/base/test/thread_test_helper.cc
@@ -11,9 +11,9 @@
 namespace base {
 
 ThreadTestHelper::ThreadTestHelper(
-    const scoped_refptr<MessageLoopProxy>& target_thread)
+    scoped_refptr<SingleThreadTaskRunner> target_thread)
     : test_result_(false),
-      target_thread_(target_thread),
+      target_thread_(target_thread.Pass()),
       done_event_(false, false) {
 }
 
diff --git a/base/test/thread_test_helper.h b/base/test/thread_test_helper.h
index f6817b5..926da73 100644
--- a/base/test/thread_test_helper.h
+++ b/base/test/thread_test_helper.h
@@ -7,7 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 
 namespace base {
@@ -19,7 +19,7 @@
 class ThreadTestHelper : public RefCountedThreadSafe<ThreadTestHelper> {
  public:
   explicit ThreadTestHelper(
-      const scoped_refptr<MessageLoopProxy>& target_thread);
+      scoped_refptr<SingleThreadTaskRunner> target_thread);
 
   // True if RunTest() was successfully executed on the target thread.
   bool Run() WARN_UNUSED_RESULT;
@@ -38,7 +38,7 @@
   void RunInThread();
 
   bool test_result_;
-  scoped_refptr<MessageLoopProxy> target_thread_;
+  scoped_refptr<SingleThreadTaskRunner> target_thread_;
   WaitableEvent done_event_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadTestHelper);
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 653961d..69a2b0d 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -89,6 +89,10 @@
         id_(id) {
   }
 
+  PlatformThreadId id() const {
+    return id_;
+  }
+
   bool is_equal(const PlatformThreadHandle& other) const {
     return handle_ == other.handle_;
   }
@@ -156,9 +160,8 @@
   static void Sleep(base::TimeDelta duration);
 
   // Sets the thread name visible to debuggers/tools. This has no effect
-  // otherwise. This name pointer is not copied internally. Thus, it must stay
-  // valid until the thread ends.
-  static void SetName(const char* name);
+  // otherwise.
+  static void SetName(const std::string& name);
 
   // Gets the thread name, if previously set by SetName.
   static const char* GetName();
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index a31f659..11e5e2e 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -64,7 +64,7 @@
 
 }  // namespace internal
 
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
   tracked_objects::ThreadData::InitializeThreadContext(name);
 
@@ -76,7 +76,7 @@
     return;
 
   // Set the name for the LWP (which gets truncated to 15 characters).
-  int err = prctl(PR_SET_NAME, name);
+  int err = prctl(PR_SET_NAME, name.c_str());
   if (err < 0 && errno != EPERM)
     DPLOG(ERROR) << "prctl(PR_SET_NAME)";
 }
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
index 7ba4eed..f4fded0 100644
--- a/base/threading/platform_thread_freebsd.cc
+++ b/base/threading/platform_thread_freebsd.cc
@@ -69,7 +69,7 @@
 }  // namespace internal
 
 // static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
   tracked_objects::ThreadData::InitializeThreadContext(name);
 
@@ -80,7 +80,7 @@
   // killall to stop working.
   if (PlatformThread::CurrentId() == getpid())
     return;
-  setproctitle("%s", name);
+  setproctitle("%s", name.c_str());
 #endif  //  !defined(OS_NACL)
 }
 
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index b72fb5b..9f74374 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -70,7 +70,7 @@
 }  // namespace internal
 
 // static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
   tracked_objects::ThreadData::InitializeThreadContext(name);
 
@@ -87,7 +87,7 @@
   // Note that glibc also has a 'pthread_setname_np' api, but it may not be
   // available everywhere and it's only benefit over using prctl directly is
   // that it can set the name of threads other than the current thread.
-  int err = prctl(PR_SET_NAME, name);
+  int err = prctl(PR_SET_NAME, name.c_str());
   // We expect EPERM failures in sandboxed processes, just ignore those.
   if (err < 0 && errno != EPERM)
     DPLOG(ERROR) << "prctl(PR_SET_NAME)";
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index fd40d79..a9c347a 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -42,14 +42,14 @@
 }
 
 // static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
   tracked_objects::ThreadData::InitializeThreadContext(name);
 
   // Mac OS X does not expose the length limit of the name, so
   // hardcode it.
   const int kMaxNameLength = 63;
-  std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+  std::string shortened_name = name.substr(0, kMaxNameLength);
   // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
   // See http://crbug.com/47058
   pthread_setname_np(shortened_name.c_str());
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index b9f7a56..aeaa7c7 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -108,15 +108,16 @@
   // have to work running on CreateThread() threads anyway, since we run code
   // on the Windows thread pool, etc.  For some background on the difference:
   //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
+  PlatformThreadId thread_id;
   void* thread_handle = CreateThread(
-      NULL, stack_size, ThreadFunc, params, flags, NULL);
+      NULL, stack_size, ThreadFunc, params, flags, &thread_id);
   if (!thread_handle) {
     delete params;
     return false;
   }
 
   if (out_thread_handle)
-    *out_thread_handle = PlatformThreadHandle(thread_handle);
+    *out_thread_handle = PlatformThreadHandle(thread_handle, thread_id);
   else
     CloseHandle(thread_handle);
   return true;
@@ -154,7 +155,7 @@
 }
 
 // static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
 
   // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
@@ -163,7 +164,7 @@
   // which would also (as a side effect) initialize the profiler in this unused
   // context, including setting up thread local storage, etc.  The performance
   // impact is not terrible, but there is no reason to do initialize it.
-  if (0 != strcmp(name, "BrokerEvent"))
+  if (name != "BrokerEvent")
     tracked_objects::ThreadData::InitializeThreadContext(name);
 
   // The debugger needs to be around to catch the name in the exception.  If
@@ -173,7 +174,7 @@
   if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
     return;
 
-  SetNameInternal(CurrentId(), name);
+  SetNameInternal(CurrentId(), name.c_str());
 }
 
 // static
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index a82a4fd..f3e88ab 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -25,30 +25,30 @@
 class PostTaskAndReplyRelay {
  public:
   PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
-                        const Closure& task, const Closure& reply)
+                        const Closure& task,
+                        const Closure& reply)
       : from_here_(from_here),
-        origin_loop_(ThreadTaskRunnerHandle::Get()) {
+        origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
     task_ = task;
     reply_ = reply;
   }
 
   ~PostTaskAndReplyRelay() {
-    DCHECK(origin_loop_->BelongsToCurrentThread());
+    DCHECK(origin_task_runner_->BelongsToCurrentThread());
     task_.Reset();
     reply_.Reset();
   }
 
   void Run() {
     task_.Run();
-    origin_loop_->PostTask(
-        from_here_,
-        Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
-             base::Unretained(this)));
+    origin_task_runner_->PostTask(
+        from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
+                         base::Unretained(this)));
   }
 
  private:
   void RunReplyAndSelfDestruct() {
-    DCHECK(origin_loop_->BelongsToCurrentThread());
+    DCHECK(origin_task_runner_->BelongsToCurrentThread());
 
     // Force |task_| to be released before |reply_| is to ensure that no one
     // accidentally depends on |task_| keeping one of its arguments alive while
@@ -62,7 +62,7 @@
   }
 
   tracked_objects::Location from_here_;
-  scoped_refptr<SingleThreadTaskRunner> origin_loop_;
+  scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
   Closure reply_;
   Closure task_;
 };
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
index 076a46d..a5b9580 100644
--- a/base/threading/post_task_and_reply_impl.h
+++ b/base/threading/post_task_and_reply_impl.h
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // This file contains the implementation shared by
-// MessageLoopProxy::PostTaskAndReply and WorkerPool::PostTaskAndReply.
+// TaskRunner::PostTaskAndReply and WorkerPool::PostTaskAndReply.
 
 #ifndef BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
 #define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
@@ -21,11 +21,11 @@
 // MessageLoop.
 //
 // If you're looking for a concrete implementation of
-// PostTaskAndReply, you probably want base::MessageLoopProxy, or you
+// PostTaskAndReply, you probably want base::SingleThreadTaskRunner, or you
 // may want base::WorkerPool.
 class PostTaskAndReplyImpl {
  public:
-  // Implementation for MessageLoopProxy::PostTaskAndReply and
+  // Implementation for TaskRunner::PostTaskAndReply and
   // WorkerPool::PostTaskAndReply.
   bool PostTaskAndReply(const tracked_objects::Location& from_here,
                         const Closure& task,
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
index 6f4a248..7bbca92 100644
--- a/base/threading/sequenced_worker_pool.cc
+++ b/base/threading/sequenced_worker_pool.cc
@@ -17,11 +17,11 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/linked_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/simple_thread.h"
 #include "base/threading/thread_local.h"
@@ -777,7 +777,6 @@
           this_worker->set_running_task_info(
               SequenceToken(task.sequence_token_id), task.shutdown_behavior);
 
-          tracked_objects::ThreadData::PrepareForStartOfRun(task.birth_tally);
           tracked_objects::TaskStopwatch stopwatch;
           stopwatch.Start();
           task.task.Run();
@@ -1158,29 +1157,26 @@
   return *token;
 }
 
-SequencedWorkerPool::SequencedWorkerPool(
-    size_t max_threads,
-    const std::string& thread_name_prefix)
-    : constructor_message_loop_(MessageLoopProxy::current()),
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+                                         const std::string& thread_name_prefix)
+    : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
       inner_(new Inner(this, max_threads, thread_name_prefix, NULL)) {
 }
 
-SequencedWorkerPool::SequencedWorkerPool(
-    size_t max_threads,
-    const std::string& thread_name_prefix,
-    TestingObserver* observer)
-    : constructor_message_loop_(MessageLoopProxy::current()),
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+                                         const std::string& thread_name_prefix,
+                                         TestingObserver* observer)
+    : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
       inner_(new Inner(this, max_threads, thread_name_prefix, observer)) {
 }
 
 SequencedWorkerPool::~SequencedWorkerPool() {}
 
 void SequencedWorkerPool::OnDestruct() const {
-  DCHECK(constructor_message_loop_.get());
   // Avoid deleting ourselves on a worker thread (which would
   // deadlock).
   if (RunsTasksOnCurrentThread()) {
-    constructor_message_loop_->DeleteSoon(FROM_HERE, this);
+    constructor_task_runner_->DeleteSoon(FROM_HERE, this);
   } else {
     delete this;
   }
@@ -1300,7 +1296,7 @@
 }
 
 void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) {
-  DCHECK(constructor_message_loop_->BelongsToCurrentThread());
+  DCHECK(constructor_task_runner_->BelongsToCurrentThread());
   inner_->Shutdown(max_new_blocking_tasks_after_shutdown);
 }
 
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
index 0b6c5f9..ee282bc 100644
--- a/base/threading/sequenced_worker_pool.h
+++ b/base/threading/sequenced_worker_pool.h
@@ -13,6 +13,7 @@
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_runner.h"
 
 namespace tracked_objects {
@@ -21,7 +22,7 @@
 
 namespace base {
 
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 
 template <class T> class DeleteHelper;
 
@@ -345,7 +346,7 @@
   class Inner;
   class Worker;
 
-  const scoped_refptr<MessageLoopProxy> constructor_message_loop_;
+  const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_;
 
   // Avoid pulling in too many headers by putting (almost) everything
   // into |inner_|.
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
index c12156e..05989a5 100644
--- a/base/threading/sequenced_worker_pool_unittest.cc
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/test/sequenced_task_runner_test_template.h"
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 028d4f4..1bc3113 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -52,7 +52,7 @@
   // Construct our full name of the form "name_prefix_/TID".
   name_.push_back('/');
   name_.append(IntToString(tid_));
-  PlatformThread::SetName(name_.c_str());
+  PlatformThread::SetName(name_);
 
   // We've initialized our new thread, signal that we're done to Start().
   event_.Signal();
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index d42ba4d..bd565c9 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
@@ -36,20 +37,6 @@
   Thread::SetThreadWasQuitProperly(true);
 }
 
-// Used to pass data to ThreadMain.  This structure is allocated on the stack
-// from within StartWithOptions.
-struct Thread::StartupData {
-  // We get away with a const reference here because of how we are allocated.
-  const Thread::Options& options;
-
-  // Used to synchronize thread startup.
-  WaitableEvent event;
-
-  explicit StartupData(const Options& opt)
-      : options(opt),
-        event(false, false) {}
-};
-
 Thread::Options::Options()
     : message_loop_type(MessageLoop::TYPE_DEFAULT),
       timer_slack(TIMER_SLACK_NONE),
@@ -71,13 +58,11 @@
 #if defined(OS_WIN)
       com_status_(NONE),
 #endif
-      started_(false),
       stopping_(false),
       running_(false),
-      startup_data_(NULL),
       thread_(0),
-      message_loop_(NULL),
-      thread_id_(kInvalidThreadId),
+      message_loop_(nullptr),
+      message_loop_timer_slack_(TIMER_SLACK_NONE),
       name_(name) {
 }
 
@@ -103,34 +88,45 @@
 
   SetThreadWasQuitProperly(false);
 
-  StartupData startup_data(options);
-  startup_data_ = &startup_data;
+  MessageLoop::Type type = options.message_loop_type;
+  if (!options.message_pump_factory.is_null())
+    type = MessageLoop::TYPE_CUSTOM;
+
+  message_loop_timer_slack_ = options.timer_slack;
+  message_loop_ = new MessageLoop(type, options.message_pump_factory);
+
+  start_event_.reset(new WaitableEvent(false, false));
 
   if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
     DLOG(ERROR) << "failed to create thread";
-    startup_data_ = NULL;
+    delete message_loop_;
+    message_loop_ = nullptr;
+    start_event_.reset();
     return false;
   }
 
-  // TODO(kinuko): Remove once crbug.com/465458 is solved.
-  tracked_objects::ScopedTracker tracking_profile_wait(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "465458 base::Thread::StartWithOptions (Wait)"));
-
-  // Wait for the thread to start and initialize message_loop_
-  base::ThreadRestrictions::ScopedAllowWait allow_wait;
-  startup_data.event.Wait();
-
-  // set it to NULL so we don't keep a pointer to some object on the stack.
-  startup_data_ = NULL;
-  started_ = true;
-
   DCHECK(message_loop_);
   return true;
 }
 
+bool Thread::StartAndWaitForTesting() {
+  bool result = Start();
+  if (!result)
+    return false;
+  WaitUntilThreadStarted();
+  return result;
+}
+
+bool Thread::WaitUntilThreadStarted() {
+  if (!start_event_)
+    return false;
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  start_event_->Wait();
+  return true;
+}
+
 void Thread::Stop() {
-  if (!started_)
+  if (!start_event_)
     return;
 
   StopSoon();
@@ -146,7 +142,7 @@
   DCHECK(!message_loop_);
 
   // The thread no longer needs to be joined.
-  started_ = false;
+  start_event_.reset();
 
   stopping_ = false;
 }
@@ -154,25 +150,32 @@
 void Thread::StopSoon() {
   // We should only be called on the same thread that started us.
 
-  // Reading thread_id_ without a lock can lead to a benign data race
-  // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
-  DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
+  DCHECK_NE(thread_id(), PlatformThread::CurrentId());
 
   if (stopping_ || !message_loop_)
     return;
 
   stopping_ = true;
-  message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+  task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
 }
 
 bool Thread::IsRunning() const {
+  // If the thread's already started (i.e. message_loop_ is non-null) and
+  // not yet requested to stop (i.e. stopping_ is false) we can just return
+  // true. (Note that stopping_ is touched only on the same thread that
+  // starts / started the new thread so we need no locking here.)
+  if (message_loop_ && !stopping_)
+    return true;
+  // Otherwise check the running_ flag, which is set to true by the new thread
+  // only while it is inside Run().
+  AutoLock lock(lock_);
   return running_;
 }
 
 void Thread::SetPriority(ThreadPriority priority) {
   // The thread must be started (and id known) for this to be
   // compatible with all platforms.
-  DCHECK_NE(thread_id_, kInvalidThreadId);
+  DCHECK(message_loop_ != nullptr);
   PlatformThread::SetThreadPriority(thread_, priority);
 }
 
@@ -193,60 +196,57 @@
 }
 
 void Thread::ThreadMain() {
-  {
-    // The message loop for this thread.
-    // Allocated on the heap to centralize any leak reports at this line.
-    scoped_ptr<MessageLoop> message_loop;
-    if (!startup_data_->options.message_pump_factory.is_null()) {
-      message_loop.reset(
-          new MessageLoop(startup_data_->options.message_pump_factory.Run()));
-    } else {
-      message_loop.reset(
-          new MessageLoop(startup_data_->options.message_loop_type));
-    }
+  // Complete the initialization of our Thread object.
+  DCHECK_EQ(thread_id(), PlatformThread::CurrentId());
+  PlatformThread::SetName(name_.c_str());
+  ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
 
-    // Complete the initialization of our Thread object.
-    thread_id_ = PlatformThread::CurrentId();
-    PlatformThread::SetName(name_.c_str());
-    ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
-    message_loop->set_thread_name(name_);
-    message_loop->SetTimerSlack(startup_data_->options.timer_slack);
-    message_loop_ = message_loop.get();
+  // Lazily initialize the message_loop so that it can run on this thread.
+  DCHECK(message_loop_);
+  scoped_ptr<MessageLoop> message_loop(message_loop_);
+  message_loop_->BindToCurrentThread();
+  message_loop_->set_thread_name(name_);
+  message_loop_->SetTimerSlack(message_loop_timer_slack_);
 
 #if defined(OS_WIN)
-    scoped_ptr<win::ScopedCOMInitializer> com_initializer;
-    if (com_status_ != NONE) {
-      com_initializer.reset((com_status_ == STA) ?
-          new win::ScopedCOMInitializer() :
-          new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
-    }
-#endif
-
-    // Let the thread do extra initialization.
-    // Let's do this before signaling we are started.
-    Init();
-
-    running_ = true;
-    startup_data_->event.Signal();
-    // startup_data_ can't be touched anymore since the starting thread is now
-    // unlocked.
-
-    Run(message_loop_);
-    running_ = false;
-
-    // Let the thread do extra cleanup.
-    CleanUp();
-
-#if defined(OS_WIN)
-    com_initializer.reset();
-#endif
-
-    // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
-    DCHECK(GetThreadWasQuitProperly());
-
-    // We can't receive messages anymore.
-    message_loop_ = NULL;
+  scoped_ptr<win::ScopedCOMInitializer> com_initializer;
+  if (com_status_ != NONE) {
+    com_initializer.reset((com_status_ == STA) ?
+        new win::ScopedCOMInitializer() :
+        new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
   }
+#endif
+
+  // Let the thread do extra initialization.
+  Init();
+
+  {
+    AutoLock lock(lock_);
+    running_ = true;
+  }
+
+  start_event_->Signal();
+
+  Run(message_loop_);
+
+  {
+    AutoLock lock(lock_);
+    running_ = false;
+  }
+
+  // Let the thread do extra cleanup.
+  CleanUp();
+
+#if defined(OS_WIN)
+  com_initializer.reset();
+#endif
+
+  // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
+  DCHECK(GetThreadWasQuitProperly());
+
+  // We can't receive messages anymore.
+  // (The message loop is destructed at the end of this block)
+  message_loop_ = NULL;
 }
 
 }  // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 5010f0e..2e19b0a 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -11,13 +11,15 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/message_loop/timer_slack.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 
 namespace base {
 
 class MessagePump;
+class WaitableEvent;
 
 // A simple thread abstraction that establishes a MessageLoop on a new thread.
 // The consumer uses the MessageLoop of the thread to cause code to execute on
@@ -45,7 +47,7 @@
     // This is ignored if message_pump_factory.is_null() is false.
     MessageLoop::Type message_loop_type;
 
-    // Specify timer slack for thread message loop.
+    // Specifies timer slack for thread message loop.
     TimerSlack timer_slack;
 
     // Used to create the MessagePump for the MessageLoop. The callback is Run()
@@ -81,7 +83,7 @@
   // init_com_with_mta(false) and then StartWithOptions() with any message loop
   // type other than TYPE_UI.
   void init_com_with_mta(bool use_mta) {
-    DCHECK(!started_);
+    DCHECK(!start_event_);
     com_status_ = use_mta ? MTA : STA;
   }
 #endif
@@ -103,6 +105,18 @@
   // callback.
   bool StartWithOptions(const Options& options);
 
+  // Starts the thread and wait for the thread to start and run initialization
+  // before returning. It's same as calling Start() and then
+  // WaitUntilThreadStarted().
+  // Note that using this (instead of Start() or StartWithOptions() causes
+  // jank on the calling thread, should be used only in testing code.
+  bool StartAndWaitForTesting();
+
+  // Blocks until the thread starts running. Called within StartAndWait().
+  // Note that calling this causes jank on the calling thread, must be used
+  // carefully for production code.
+  bool WaitUntilThreadStarted();
+
   // Signals the thread to exit and returns once the thread has exited.  After
   // this method returns, the Thread object is completely reset and may be used
   // as if it were newly constructed (i.e., Start may be called again).
@@ -156,7 +170,7 @@
   // 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_proxy();
+    return message_loop_->task_runner();
   }
 
   // Returns the name of this thread (for display in debugger too).
@@ -166,7 +180,7 @@
   PlatformThreadHandle thread_handle() { return thread_; }
 
   // The thread ID.
-  PlatformThreadId thread_id() const { return thread_id_; }
+  PlatformThreadId thread_id() const { return thread_.id(); }
 
   // Returns true if the thread has been started, and not yet stopped.
   bool IsRunning() const;
@@ -208,19 +222,13 @@
   ComStatus com_status_;
 #endif
 
-  // Whether we successfully started the thread.
-  bool started_;
-
   // If true, we're in the middle of stopping, and shouldn't access
   // |message_loop_|. It may non-NULL and invalid.
   bool stopping_;
 
   // True while inside of Run().
   bool running_;
-
-  // Used to pass data to ThreadMain.
-  struct StartupData;
-  StartupData* startup_data_;
+  mutable base::Lock lock_;  // Protects running_.
 
   // The thread's handle.
   PlatformThreadHandle thread_;
@@ -229,12 +237,16 @@
   // by the created thread.
   MessageLoop* message_loop_;
 
-  // Our thread's ID.
-  PlatformThreadId thread_id_;
+  // Stores Options::timer_slack_ until the message loop has been bound to
+  // a thread.
+  TimerSlack message_loop_timer_slack_;
 
   // The name of the thread.  Used for debugging purposes.
   std::string name_;
 
+  // Non-null if the thread has successfully started.
+  scoped_ptr<WaitableEvent> start_event_;
+
   friend void ThreadQuitHelper();
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
index 7c85c1b..56cfa27 100644
--- a/base/threading/thread_id_name_manager.cc
+++ b/base/threading/thread_id_name_manager.cc
@@ -48,17 +48,16 @@
       name_to_interned_name_[kDefaultName];
 }
 
-void ThreadIdNameManager::SetName(PlatformThreadId id, const char* name) {
-  std::string str_name(name);
-
+void ThreadIdNameManager::SetName(PlatformThreadId id,
+                                  const std::string& name) {
   AutoLock locked(lock_);
-  NameToInternedNameMap::iterator iter = name_to_interned_name_.find(str_name);
+  NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name);
   std::string* leaked_str = NULL;
   if (iter != name_to_interned_name_.end()) {
     leaked_str = iter->second;
   } else {
-    leaked_str = new std::string(str_name);
-    name_to_interned_name_[str_name] = leaked_str;
+    leaked_str = new std::string(name);
+    name_to_interned_name_[name] = leaked_str;
   }
 
   ThreadIdToHandleMap::iterator id_to_handle_iter =
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
index 0ea59df..927d25f 100644
--- a/base/threading/thread_id_name_manager.h
+++ b/base/threading/thread_id_name_manager.h
@@ -27,7 +27,7 @@
   void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
 
   // Set the name for the given id.
-  void SetName(PlatformThreadId id, const char* name);
+  void SetName(PlatformThreadId id, const std::string& name);
 
   // Get the name for the given id.
   const char* GetName(PlatformThreadId id);
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
index b5953d5..b17c681 100644
--- a/base/threading/thread_id_name_manager_unittest.cc
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -21,8 +21,8 @@
   base::Thread thread_a(kAThread);
   base::Thread thread_b(kBThread);
 
-  thread_a.Start();
-  thread_b.Start();
+  thread_a.StartAndWaitForTesting();
+  thread_b.StartAndWaitForTesting();
 
   EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
   EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id()));
@@ -35,10 +35,10 @@
   base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
   base::Thread thread_a(kAThread);
 
-  thread_a.Start();
+  thread_a.StartAndWaitForTesting();
   {
     base::Thread thread_b(kBThread);
-    thread_b.Start();
+    thread_b.StartAndWaitForTesting();
     thread_b.Stop();
   }
   EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
@@ -51,12 +51,12 @@
   base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
   base::Thread thread_a(kAThread);
 
-  thread_a.Start();
+  thread_a.StartAndWaitForTesting();
   base::PlatformThreadId a_id = thread_a.thread_id();
   EXPECT_STREQ(kAThread, manager->GetName(a_id));
   thread_a.Stop();
 
-  thread_a.Start();
+  thread_a.StartAndWaitForTesting();
   EXPECT_STREQ("", manager->GetName(a_id));
   EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
   thread_a.Stop();
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index a08cc5b..3bc9fb4 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -5,7 +5,9 @@
 #include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
@@ -54,12 +56,9 @@
   base::TimeTicks ThreadNow(base::Thread* thread) {
     base::WaitableEvent done(false, false);
     base::TimeTicks ticks;
-    thread->message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(&ThreadPerfTest::TimeOnThread,
-                   base::Unretained(this),
-                   &ticks,
-                   &done));
+    thread->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadPerfTest::TimeOnThread,
+                              base::Unretained(this), &ticks, &done));
     done.Wait();
     return ticks;
   }
@@ -128,10 +127,9 @@
       FinishMeasurement();
       return;
     }
-    NextThread(hops)->message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &ThreadPerfTest::PingPong, base::Unretained(this), hops - 1));
+    NextThread(hops)->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadPerfTest::PingPong, base::Unretained(this),
+                              hops - 1));
   }
 };
 
@@ -198,11 +196,9 @@
   void PingPong(int hops) override {
     remaining_hops_ = hops;
     for (size_t i = 0; i < threads_.size(); i++) {
-      threads_[i]->message_loop_proxy()->PostTask(
-          FROM_HERE,
-          base::Bind(&EventPerfTest::WaitAndSignalOnThread,
-                     base::Unretained(this),
-                     i));
+      threads_[i]->task_runner()->PostTask(
+          FROM_HERE, base::Bind(&EventPerfTest::WaitAndSignalOnThread,
+                                base::Unretained(this), i));
     }
 
     // Kick off the Signal ping-ponging.
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index f4d024f..e86c758 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -7,7 +7,8 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -144,7 +145,7 @@
   EXPECT_TRUE(a.IsRunning());
 
   bool was_invoked = false;
-  a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
+  a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
 
   // wait for the task to run (we could use a kernel event here
   // instead to avoid busy waiting, but this is sufficient for
@@ -165,14 +166,12 @@
     // Test that all events are dispatched before the Thread object is
     // destroyed.  We do this by dispatching a sleep event before the
     // event that will toggle our sentinel value.
-    a.message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            static_cast<void (*)(base::TimeDelta)>(
-                &base::PlatformThread::Sleep),
-            base::TimeDelta::FromMilliseconds(20)));
-    a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue,
-                                                     &was_invoked));
+    a.task_runner()->PostTask(
+        FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
+                                  &base::PlatformThread::Sleep),
+                              base::TimeDelta::FromMilliseconds(20)));
+    a.task_runner()->PostTask(FROM_HERE,
+                              base::Bind(&ToggleValue, &was_invoked));
   }
   EXPECT_TRUE(was_invoked);
 }
@@ -195,11 +194,12 @@
   EXPECT_EQ("ThreadName", a.thread_name());
 }
 
-// Make sure we can't use a thread between Start() and Init().
+// Make sure Init() is called after Start() and before
+// WaitUntilThreadInitialized() returns.
 TEST_F(ThreadTest, SleepInsideInit) {
   SleepInsideInitThread t;
   EXPECT_FALSE(t.InitCalled());
-  t.Start();
+  t.StartAndWaitForTesting();
   EXPECT_TRUE(t.InitCalled());
 }
 
@@ -221,7 +221,7 @@
 
     // Register an observer that writes into |captured_events| once the
     // thread's message loop is destroyed.
-    t.message_loop()->PostTask(
+    t.task_runner()->PostTask(
         FROM_HERE, base::Bind(&RegisterDestructionObserver,
                               base::Unretained(&loop_destruction_observer)));
 
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
index 769119e..c063799 100644
--- a/base/threading/watchdog.cc
+++ b/base/threading/watchdog.cc
@@ -169,7 +169,7 @@
 
 void Watchdog::ThreadDelegate::SetThreadName() const {
   std::string name = watchdog_->thread_watched_name_ + " Watchdog";
-  PlatformThread::SetName(name.c_str());
+  PlatformThread::SetName(name);
   DVLOG(1) << "Watchdog active: " << name;
 }
 
diff --git a/base/threading/worker_pool.h b/base/threading/worker_pool.h
index 333b495..a52a414 100644
--- a/base/threading/worker_pool.h
+++ b/base/threading/worker_pool.h
@@ -36,7 +36,7 @@
   static bool PostTask(const tracked_objects::Location& from_here,
                        const base::Closure& task, bool task_is_slow);
 
-  // Just like MessageLoopProxy::PostTaskAndReply, except the destination
+  // Just like TaskRunner::PostTaskAndReply, except the destination
   // for |task| is a worker thread and you can specify |task_is_slow| just
   // like you can for PostTask above.
   static bool PostTaskAndReply(const tracked_objects::Location& from_here,
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
index 32a5e92..349b5d7 100644
--- a/base/threading/worker_pool_posix.cc
+++ b/base/threading/worker_pool_posix.cc
@@ -77,7 +77,7 @@
   const std::string name = base::StringPrintf(
       "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
   // Note |name.c_str()| must remain valid for for the whole life of the thread.
-  PlatformThread::SetName(name.c_str());
+  PlatformThread::SetName(name);
 
   for (;;) {
     PendingTask pending_task = pool_->WaitForTask();
@@ -87,7 +87,6 @@
         "src_file", pending_task.posted_from.file_name(),
         "src_func", pending_task.posted_from.function_name());
 
-    tracked_objects::ThreadData::PrepareForStartOfRun(pending_task.birth_tally);
     tracked_objects::TaskStopwatch stopwatch;
     stopwatch.Start();
     pending_task.task.Run();
diff --git a/base/threading/worker_pool_win.cc b/base/threading/worker_pool_win.cc
index 5469439..1b0ade5 100644
--- a/base/threading/worker_pool_win.cc
+++ b/base/threading/worker_pool_win.cc
@@ -25,8 +25,6 @@
                "src_file", pending_task->posted_from.file_name(),
                "src_func", pending_task->posted_from.function_name());
 
-  tracked_objects::ThreadData::PrepareForStartOfRun(pending_task->birth_tally);
-
   g_worker_pool_running_on_this_thread.Get().Set(true);
 
   tracked_objects::TaskStopwatch stopwatch;
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 4f3819d..633ab90 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -6,13 +6,10 @@
   sources = [
     "java_heap_dump_provider_android.cc",
     "java_heap_dump_provider_android.h",
-    "memory_allocator_attributes_type_info.cc",
-    "memory_allocator_attributes_type_info.h",
     "memory_allocator_dump.cc",
     "memory_allocator_dump.h",
     "memory_dump_manager.cc",
     "memory_dump_manager.h",
-    "memory_dump_provider.cc",
     "memory_dump_provider.h",
     "memory_dump_request_args.h",
     "memory_dump_session_state.cc",
@@ -88,7 +85,7 @@
 source_set("trace_event_unittests") {
   testonly = true
   sources = [
-    "memory_allocator_attributes_type_info_unittest.cc",
+    "java_heap_dump_provider_android_unittest.cc",
     "memory_allocator_dump_unittest.cc",
     "memory_dump_manager_unittest.cc",
     "process_memory_maps_dump_provider_unittest.cc",
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
index 07cf80e..f62e356 100644
--- a/base/trace_event/etw_manifest/BUILD.gn
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -5,11 +5,8 @@
 assert(is_win, "This only runs on Windows.")
 
 # Makes the .h/.rc files from the .man file.
-action("chrome_events_win") {
-  visibility = [
-    "//base/trace_event/*",
-    "//chrome:main_dll",
-  ]
+action("chrome_events_win_generate") {
+  visibility = [ ":*" ]
   script = "build/message_compiler.py"
 
   sources = [
@@ -35,3 +32,17 @@
     rebase_path("chrome_events_win.man", root_build_dir),
   ]
 }
+
+# Compile the generated files.
+source_set("chrome_events_win") {
+  visibility = [
+    "//base/trace_event/*",
+    "//chrome:main_dll",
+  ]
+
+  sources = get_target_outputs(":chrome_events_win_generate")
+
+  deps = [
+    ":chrome_events_win_generate",
+  ]
+}
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
index b0a8712..b2f0eb8 100644
--- a/base/trace_event/etw_manifest/etw_manifest.gyp
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -6,7 +6,9 @@
     {
       # GN version: //base/trace_event/etw_manifest/BUILD.gn
       'target_name': 'etw_manifest',
-      'type': 'static_library',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'hard_dependency': 1,
       'conditions': [
         ['OS=="win"', {
           'sources': [
diff --git a/base/trace_event/java_heap_dump_provider_android.cc b/base/trace_event/java_heap_dump_provider_android.cc
index aa193ab..2a84b81 100644
--- a/base/trace_event/java_heap_dump_provider_android.cc
+++ b/base/trace_event/java_heap_dump_provider_android.cc
@@ -10,13 +10,6 @@
 namespace base {
 namespace trace_event {
 
-namespace {
-
-const char kDumperFriendlyName[] = "JavaHeap";
-const char kDumperName[] = "java_heap";
-
-}  // namespace
-
 // static
 JavaHeapDumpProvider* JavaHeapDumpProvider::GetInstance() {
   return Singleton<JavaHeapDumpProvider,
@@ -31,23 +24,20 @@
 
 // Called at trace dump point time. Creates a snapshot with the memory counters
 // for the current process.
-bool JavaHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
-  MemoryAllocatorDump* dump =
-      pmd->CreateAllocatorDump(kDumperName, MemoryAllocatorDump::kRootHeap);
+bool JavaHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("java_heap");
 
   // These numbers come from java.lang.Runtime stats.
   long total_heap_size = 0;
   long free_heap_size = 0;
   android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
-  dump->set_physical_size_in_bytes(total_heap_size);
-  dump->set_allocated_objects_count(0);
-  dump->set_allocated_objects_size_in_bytes(total_heap_size - free_heap_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                  MemoryAllocatorDump::kUnitsBytes, total_heap_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                  MemoryAllocatorDump::kUnitsBytes,
+                  total_heap_size - free_heap_size);
   return true;
 }
 
-const char* JavaHeapDumpProvider::GetFriendlyName() const {
-  return kDumperFriendlyName;
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android.h b/base/trace_event/java_heap_dump_provider_android.h
index 8280751..2f31047 100644
--- a/base/trace_event/java_heap_dump_provider_android.h
+++ b/base/trace_event/java_heap_dump_provider_android.h
@@ -12,13 +12,12 @@
 namespace trace_event {
 
 // Dump provider which collects process-wide memory stats.
-class JavaHeapDumpProvider : public MemoryDumpProvider {
+class BASE_EXPORT JavaHeapDumpProvider : public MemoryDumpProvider {
  public:
   static JavaHeapDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool DumpInto(ProcessMemoryDump* pmd) override;
-  const char* GetFriendlyName() const override;
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
diff --git a/base/trace_event/java_heap_dump_provider_android_unittest.cc b/base/trace_event/java_heap_dump_provider_android_unittest.cc
new file mode 100644
index 0000000..bbefba5
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
+  auto jhdp = JavaHeapDumpProvider::GetInstance();
+  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+
+  jhdp->OnMemoryDump(pmd.get());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index 7d9931c..c04b858 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -11,12 +11,6 @@
 namespace base {
 namespace trace_event {
 
-namespace {
-
-const char kDumperFriendlyName[] = "Malloc";
-
-}  // namespace
-
 // static
 MallocDumpProvider* MallocDumpProvider::GetInstance() {
   return Singleton<MallocDumpProvider,
@@ -31,12 +25,11 @@
 
 // Called at trace dump point time. Creates a snapshot the memory counters for
 // the current process.
-bool MallocDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool MallocDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
   struct mallinfo info = mallinfo();
   DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
 
-  MemoryAllocatorDump* dump =
-      pmd->CreateAllocatorDump("malloc", MemoryAllocatorDump::kRootHeap);
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("malloc");
   if (!dump)
     return false;
 
@@ -45,20 +38,15 @@
   // |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
   // dlmalloc the total is given by |arena| + |hblkhd|.
   // For more details see link: http://goo.gl/fMR8lF.
-  dump->set_physical_size_in_bytes(info.arena + info.hblkhd);
-
-  // mallinfo doesn't support any allocated object count.
-  dump->set_allocated_objects_count(0);
+  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                  MemoryAllocatorDump::kUnitsBytes, info.arena + info.hblkhd);
 
   // Total allocated space is given by |uordblks|.
-  dump->set_allocated_objects_size_in_bytes(info.uordblks);
+  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                  MemoryAllocatorDump::kUnitsBytes, info.uordblks);
 
   return true;
 }
 
-const char* MallocDumpProvider::GetFriendlyName() const {
-  return kDumperFriendlyName;
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
index b6f6973..ec8683a 100644
--- a/base/trace_event/malloc_dump_provider.h
+++ b/base/trace_event/malloc_dump_provider.h
@@ -19,8 +19,7 @@
   static MallocDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool DumpInto(ProcessMemoryDump* pmd) override;
-  const char* GetFriendlyName() const override;
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<MallocDumpProvider>;
diff --git a/base/trace_event/memory_allocator_attributes_type_info.cc b/base/trace_event/memory_allocator_attributes_type_info.cc
deleted file mode 100644
index 7d1e61c..0000000
--- a/base/trace_event/memory_allocator_attributes_type_info.cc
+++ /dev/null
@@ -1,61 +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.
-
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-base::LazyInstance<const std::string> kNotFound = LAZY_INSTANCE_INITIALIZER;
-
-std::string GetKey(const std::string& allocator_name,
-                   const std::string& attribute_name) {
-  return allocator_name + "/" + attribute_name;
-}
-}  // namespace
-
-MemoryAllocatorAttributesTypeInfo::MemoryAllocatorAttributesTypeInfo() {
-}
-
-MemoryAllocatorAttributesTypeInfo::~MemoryAllocatorAttributesTypeInfo() {
-}
-
-const std::string& MemoryAllocatorAttributesTypeInfo::Get(
-    const std::string& allocator_name,
-    const std::string& attribute_name) const {
-  auto it = type_info_map_.find(GetKey(allocator_name, attribute_name));
-  if (it == type_info_map_.end())
-    return kNotFound.Get();
-  return it->second;
-}
-
-void MemoryAllocatorAttributesTypeInfo::Set(const std::string& allocator_name,
-                                            const std::string& attribute_name,
-                                            const std::string& attribute_type) {
-  std::string key = GetKey(allocator_name, attribute_name);
-  DCHECK_EQ(0u, type_info_map_.count(key));
-  type_info_map_[key] = attribute_type;
-}
-
-bool MemoryAllocatorAttributesTypeInfo::Exists(
-    const std::string& allocator_name,
-    const std::string& attribute_name) const {
-  return type_info_map_.count(GetKey(allocator_name, attribute_name)) == 1;
-}
-
-void MemoryAllocatorAttributesTypeInfo::Update(
-    const MemoryAllocatorAttributesTypeInfo& other) {
-  for (auto it = other.type_info_map_.begin();
-       it != other.type_info_map_.end(); ++it) {
-    bool no_duplicates = type_info_map_.insert(*it).second;
-    DCHECK(no_duplicates) << "Duplicated allocator attribute " << it->first;
-  }
-}
-
-}  // namespace trace_event
-}  // namespace base
diff --git a/base/trace_event/memory_allocator_attributes_type_info.h b/base/trace_event/memory_allocator_attributes_type_info.h
deleted file mode 100644
index c3986ae..0000000
--- a/base/trace_event/memory_allocator_attributes_type_info.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
-#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-
-namespace base {
-namespace trace_event {
-
-// A dictionary of "allocator_name/attribute_name" -> "attribute_type" which
-// supports merging and enforces duplicate checking.
-class BASE_EXPORT MemoryAllocatorAttributesTypeInfo {
- public:
-  MemoryAllocatorAttributesTypeInfo();
-  ~MemoryAllocatorAttributesTypeInfo();
-
-  // Returns the attribute type, or an empty string if not found.
-  const std::string& Get(const std::string& allocator_name,
-                         const std::string& attribute_name) const;
-
-  // Refer to tools/perf/unit-info.json for the semantics of |attribute_type|.
-  void Set(const std::string& allocator_name,
-           const std::string& attribute_name,
-           const std::string& attribute_type);
-
-  // Checks whether a given {allocator_name, attribute_name} declaration exists.
-  bool Exists(const std::string& allocator_name,
-              const std::string& attribute_name) const;
-
-  // Merges the attribute types declared in |other| into this.
-  void Update(const MemoryAllocatorAttributesTypeInfo& other);
-
- private:
-  // "allocator_name/attribute_name" -> attribute_type.
-  hash_map<std::string, std::string> type_info_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorAttributesTypeInfo);
-};
-
-}  // namespace trace_event
-}  // namespace base
-
-#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_TYPE_INFO_H_
diff --git a/base/trace_event/memory_allocator_attributes_type_info_unittest.cc b/base/trace_event/memory_allocator_attributes_type_info_unittest.cc
deleted file mode 100644
index 5f69fae..0000000
--- a/base/trace_event/memory_allocator_attributes_type_info_unittest.cc
+++ /dev/null
@@ -1,59 +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.
-
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-TEST(MemoryAllocatorAttributesTypeInfoTest, BasicTest) {
-  MemoryAllocatorAttributesTypeInfo attrs;
-  EXPECT_EQ("", attrs.Get("non_existing_alloc", "non_existing_attr"));
-
-  attrs.Set("alloc", "attr", "type");
-  EXPECT_TRUE(attrs.Exists("alloc", "attr"));
-  EXPECT_FALSE(attrs.Exists("alloc", "foo"));
-  EXPECT_FALSE(attrs.Exists("foo", "attr"));
-  EXPECT_EQ("type", attrs.Get("alloc", "attr"));
-
-  attrs.Set("alloc2", "attr", "type2");
-  EXPECT_TRUE(attrs.Exists("alloc2", "attr"));
-  EXPECT_FALSE(attrs.Exists("alloc2", "foo"));
-  EXPECT_EQ("type", attrs.Get("alloc", "attr"));
-  EXPECT_EQ("type2", attrs.Get("alloc2", "attr"));
-
-  MemoryAllocatorAttributesTypeInfo other_attrs;
-  other_attrs.Set("other_alloc", "other_attr", "other_type");
-  other_attrs.Set("other_alloc", "attr", "other_type2");
-  other_attrs.Set("other_alloc_2", "other_attr", "other_type");
-  other_attrs.Set("other_alloc_2", "attr", "other_type3");
-
-  // Check the merging logic.
-  attrs.Update(other_attrs);
-  EXPECT_EQ("other_type", attrs.Get("other_alloc", "other_attr"));
-  EXPECT_EQ("other_type2", attrs.Get("other_alloc", "attr"));
-  EXPECT_EQ("other_type", attrs.Get("other_alloc_2", "other_attr"));
-  EXPECT_EQ("other_type3", attrs.Get("other_alloc_2", "attr"));
-  EXPECT_EQ("type", attrs.Get("alloc", "attr"));
-  EXPECT_EQ("type2", attrs.Get("alloc2", "attr"));
-  EXPECT_FALSE(other_attrs.Exists("alloc", "attr"));
-  EXPECT_FALSE(other_attrs.Exists("alloc2", "attr"));
-}
-
-// DEATH tests are not supported in Android / iOS.
-#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
-TEST(MemoryAllocatorAttributesTypeInfoTest, DuplicatesDeathTest) {
-  MemoryAllocatorAttributesTypeInfo attrs;
-  attrs.Set("alloc", "attr", "type");
-  MemoryAllocatorAttributesTypeInfo conflicting_attrs;
-  conflicting_attrs.Set("alloc", "attr", "type2");
-  ASSERT_DEATH(attrs.Set("alloc", "attr", "other_type"), "");
-  ASSERT_DEATH(attrs.Update(conflicting_attrs), "");
-}
-#endif
-
-}  // namespace trace_event
-}  // namespace base
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index 1d2fb3f..77c32ec 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -15,114 +15,105 @@
 namespace base {
 namespace trace_event {
 
-// static
-const char MemoryAllocatorDump::kRootHeap[] = "";
-
-// static
-std::string MemoryAllocatorDump::GetAbsoluteName(
-    const std::string& allocator_name,
-    const std::string& heap_name) {
-  return allocator_name + (heap_name == kRootHeap ? "" : "/" + heap_name);
+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
 
-MemoryAllocatorDump::MemoryAllocatorDump(const std::string& allocator_name,
-                                         const std::string& heap_name,
+const char MemoryAllocatorDump::kNameOuterSize[] = "outer_size";
+const char MemoryAllocatorDump::kNameInnerSize[] = "inner_size";
+const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
+const char MemoryAllocatorDump::kTypeString[] = "string";
+const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
+const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
                                          ProcessMemoryDump* process_memory_dump)
-    : allocator_name_(allocator_name),
-      heap_name_(heap_name),
-      process_memory_dump_(process_memory_dump),
-      physical_size_in_bytes_(0),
-      allocated_objects_count_(0),
-      allocated_objects_size_in_bytes_(0) {
-  // The allocator name cannot be empty or contain slash separators.
-  DCHECK(!allocator_name.empty());
-  DCHECK_EQ(std::string::npos, allocator_name.find_first_of('/'));
+    : absolute_name_(absolute_name), process_memory_dump_(process_memory_dump) {
+  // The |absolute_name| cannot be empty.
+  DCHECK(!absolute_name.empty());
 
-  // The heap_name can be empty and contain slash separator, but not
-  // leading or trailing ones.
-  DCHECK(heap_name.empty() ||
-         (heap_name[0] != '/' && *heap_name.rbegin() != '/'));
+  // The |absolute_name| can contain slash separator, but not leading or
+  // trailing ones.
+  DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
 
   // Dots are not allowed anywhere as the underlying base::DictionaryValue
   // would treat them magically and split in sub-nodes, which is not intended.
-  DCHECK_EQ(std::string::npos, allocator_name.find_first_of('.'));
-  DCHECK_EQ(std::string::npos, heap_name.find_first_of('.'));
+  DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
 }
 
 MemoryAllocatorDump::~MemoryAllocatorDump() {
 }
 
-void MemoryAllocatorDump::SetAttribute(const std::string& name, int value) {
-  DCHECK(GetAttributesTypeInfo().Exists(allocator_name_, name))
-      << "attribute '" << name << "' not declared."
-      << "See MemoryDumpProvider.DeclareAllocatorAttribute()";
-  attributes_values_.SetInteger(name, value);
+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());
 }
 
-std::string MemoryAllocatorDump::GetAbsoluteName() const {
-  return GetAbsoluteName(allocator_name_, heap_name_);
+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;
 }
 
-int MemoryAllocatorDump::GetIntegerAttribute(const std::string& name) const {
-  int value = -1;
-  bool res = attributes_values_.GetInteger(name, &value);
-  DCHECK(res) << "Attribute '" << name << "' not found";
-  return value;
+void MemoryAllocatorDump::AddScalar(const std::string& name,
+                                    const char* units,
+                                    uint64 value) {
+  scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
+  Add(name, kTypeScalar, units, hex_value.Pass());
+}
+
+void MemoryAllocatorDump::AddString(const std::string& name,
+                                    const char* units,
+                                    const std::string& value) {
+  scoped_ptr<Value> str_value(new StringValue(value));
+  Add(name, kTypeString, units, str_value.Pass());
 }
 
 void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
-  static const char kHexFmt[] = "%" PRIx64;
-
-  value->BeginDictionary(GetAbsoluteName().c_str());
+  value->BeginDictionary(absolute_name_.c_str());
   value->BeginDictionary("attrs");
 
-  // TODO(primiano): these hard-coded types are temporary to transition to the
-  // new generalized attribute format. This code will be refactored by the end
-  // of May 2015.
-  value->BeginDictionary("outer_size");
-  value->SetString("type", "scalar");
-  value->SetString("units", "bytes");
-  value->SetString("value", StringPrintf(kHexFmt, physical_size_in_bytes_));
-  value->EndDictionary();
-
-  value->BeginDictionary("inner_size");
-  value->SetString("type", "scalar");
-  value->SetString("units", "bytes");
-  value->SetString("value",
-                   StringPrintf(kHexFmt, allocated_objects_size_in_bytes_));
-  value->EndDictionary();
-
-  value->BeginDictionary("objects_count");
-  value->SetString("type", "scalar");
-  value->SetString("units", "objects");
-  value->SetString("value", StringPrintf(kHexFmt, allocated_objects_count_));
-  value->EndDictionary();
-
-  // Copy all the extra attributes.
-  for (DictionaryValue::Iterator it(attributes_values_); !it.IsAtEnd();
-       it.Advance()) {
-    const std::string& attr_name = it.key();
-    const Value& attr_value = it.value();
-    value->BeginDictionary(attr_name.c_str());
-    value->SetValue("value", attr_value.DeepCopy());
-
-    const std::string& attr_type =
-        GetAttributesTypeInfo().Get(allocator_name_, attr_name);
-    DCHECK(!attr_type.empty());
-    value->SetString("type", "scalar");
-    value->SetString("units", attr_type);
-
-    value->EndDictionary();  // "arg_name": { "type": "...", "value": "..." }
-  }
+  for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
+    value->SetValue(it.key().c_str(), it.value().DeepCopy());
 
   value->EndDictionary();  // "attrs": { ... }
   value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
 }
 
-const MemoryAllocatorAttributesTypeInfo&
-MemoryAllocatorDump::GetAttributesTypeInfo() const {
-  return process_memory_dump_->session_state()->allocators_attributes_type_info;
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index 1c786ab..1bb27f9 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -8,7 +8,6 @@
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
 #include "base/values.h"
 
 namespace base {
@@ -21,58 +20,45 @@
 // Data model for user-land memory allocator dumps.
 class BASE_EXPORT MemoryAllocatorDump {
  public:
-  // Returns the absolute name for a given (|allocator_name|,|heap_name|) tuple.
-  static std::string GetAbsoluteName(const std::string& allocator_name,
-                                     const std::string& heap_name);
-
-  // Use as argument for |heap_name| when the allocator has only one root heap.
-  static const char kRootHeap[];
-
   // MemoryAllocatorDump is owned by ProcessMemoryDump.
-  MemoryAllocatorDump(const std::string& allocator_name,
-                      const std::string& heap_name,
+  MemoryAllocatorDump(const std::string& absolute_name,
                       ProcessMemoryDump* process_memory_dump);
   ~MemoryAllocatorDump();
 
-  // Name of the allocator, a plain string with no separators (e.g, "malloc").
-  const std::string& allocator_name() const { return allocator_name_; }
+  // Standard attribute name to model total space requested by the allocator
+  // (e.g., amount of pages requested to the system).
+  static const char kNameOuterSize[];
 
-  // Name of the heap being dumped, either: "heap", "heap/subheap" or kRootHeap
-  // if the allocator has just one root heap.
-  const std::string& heap_name() const { return heap_name_; }
+  // 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.
+  static const char kUnitsBytes[];    // Unit name to represent bytes.
+  static const char kUnitsObjects[];  // Unit name to represent #objects.
 
   // Absolute name, unique within the scope of an entire ProcessMemoryDump.
-  // In practice this is "allocator_name/heap/subheap".
-  std::string GetAbsoluteName() const;
+  const std::string& absolute_name() const { return absolute_name_; }
 
-  // Inner size: Bytes requested by clients of the allocator, without accounting
-  // for any metadata or allocator-specific bookeeping structs.
-  void set_allocated_objects_size_in_bytes(uint64 value) {
-    allocated_objects_size_in_bytes_ = value;
-  }
-  uint64 allocated_objects_size_in_bytes() const {
-    return allocated_objects_size_in_bytes_;
-  }
+  // 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;
 
-  // Outer size: bytes requested to the system to handle all the allocations,
-  // including any allocator-internal metadata / bookeeping structs. For
-  // instance, in the case of an allocator which gets pages to the system via
-  // mmap() or similar, this is the number of requested pages * 4k.
-  void set_physical_size_in_bytes(uint64 value) {
-    physical_size_in_bytes_ = value;
-  }
-  uint64 physical_size_in_bytes() const { return physical_size_in_bytes_; }
-
-  // Number of objects allocated, if known, or 0 if not available.
-  void set_allocated_objects_count(uint64 value) {
-    allocated_objects_count_ = value;
-  }
-  uint64 allocated_objects_count() const { return allocated_objects_count_; }
-
-  // Get/Set extra attributes. The attributes name must have been previously
-  // declared through MemoryDumpProvider.DeclareAllocatorAttribute().
-  void SetAttribute(const std::string& name, int value);
-  int GetIntegerAttribute(const std::string& name) const;
+  // Helper setter for scalar attributes.
+  void AddScalar(const std::string& name, const char* units, uint64 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;
@@ -82,18 +68,10 @@
     return process_memory_dump_;
   }
 
-  // Retrieves the map of allocator attributes types, which is shared by all
-  // MemoryAllocatorDump(s) across all ProcessMemoryDump(s) per tracing session.
-  const MemoryAllocatorAttributesTypeInfo& GetAttributesTypeInfo() const;
-
  private:
-  const std::string allocator_name_;
-  const std::string heap_name_;
+  const std::string absolute_name_;
   ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
-  uint64 physical_size_in_bytes_;
-  uint64 allocated_objects_count_;
-  uint64 allocated_objects_size_in_bytes_;
-  DictionaryValue attributes_values_;
+  DictionaryValue attributes_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
 };
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index 110a25d..0b2cbdf 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/trace_event/memory_allocator_dump.h"
 
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.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"
@@ -17,80 +19,115 @@
 
 class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
  public:
-  FakeMemoryAllocatorDumpProvider() {
-    DeclareAllocatorAttribute("foobar_allocator", "attr1", "count");
-    DeclareAllocatorAttribute("foobar_allocator", "attr2", "bytes");
-  }
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+    MemoryAllocatorDump* root_heap =
+        pmd->CreateAllocatorDump("foobar_allocator");
 
-  bool DumpInto(ProcessMemoryDump* pmd) override {
-    MemoryAllocatorDump* root_heap = pmd->CreateAllocatorDump(
-        "foobar_allocator", MemoryAllocatorDump::kRootHeap);
-    root_heap->set_physical_size_in_bytes(4096);
-    root_heap->set_allocated_objects_count(42);
-    root_heap->set_allocated_objects_size_in_bytes(1000);
-    root_heap->SetAttribute("attr1", 1234);
-    root_heap->SetAttribute("attr2", 99);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                         MemoryAllocatorDump::kUnitsBytes, 4096);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                         MemoryAllocatorDump::kUnitsBytes, 1000);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                         MemoryAllocatorDump::kUnitsObjects, 42);
+    root_heap->AddScalar("attr1", "units1", 1234);
+    root_heap->AddString("attr2", "units2", "string_value");
 
     MemoryAllocatorDump* sub_heap =
-        pmd->CreateAllocatorDump("foobar_allocator", "sub_heap");
-    sub_heap->set_physical_size_in_bytes(1);
-    sub_heap->set_allocated_objects_count(2);
-    sub_heap->set_allocated_objects_size_in_bytes(3);
+        pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                        MemoryAllocatorDump::kUnitsBytes, 1);
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                        MemoryAllocatorDump::kUnitsBytes, 2);
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                        MemoryAllocatorDump::kUnitsObjects, 3);
 
-    pmd->CreateAllocatorDump("foobar_allocator", "sub_heap/empty");
+    pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
     // Leave the rest of sub heap deliberately uninitialized, to check that
     // CreateAllocatorDump returns a properly zero-initialized object.
 
     return true;
   }
-
-  const char* GetFriendlyName() const override { return "FooBar Allocator"; }
 };
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+                    const std::string& name,
+                    const char* expected_type,
+                    const char* expected_units,
+                    const std::string& expected_value) {
+  const char* attr_type;
+  const char* attr_units;
+  const Value* attr_value;
+  std::string attr_str_value;
+  bool res = dump->Get(name, &attr_type, &attr_units, &attr_value);
+  EXPECT_TRUE(res);
+  if (!res)
+    return;
+  EXPECT_EQ(expected_type, std::string(attr_type));
+  EXPECT_EQ(expected_units, std::string(attr_units));
+  EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
+  EXPECT_EQ(expected_value, attr_str_value);
+}
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+                    const std::string& name,
+                    const char* expected_type,
+                    const char* expected_units,
+                    uint64 expected_value) {
+  CheckAttribute(dump, name, expected_type, expected_units,
+                 StringPrintf("%" PRIx64, expected_value));
+}
 }  // namespace
 
 TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
   FakeMemoryAllocatorDumpProvider fmadp;
   ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
-  pmd.session_state()->allocators_attributes_type_info.Update(
-      fmadp.allocator_attributes_type_info());
 
-  fmadp.DumpInto(&pmd);
+  fmadp.OnMemoryDump(&pmd);
 
   ASSERT_EQ(3u, pmd.allocator_dumps().size());
 
   const MemoryAllocatorDump* root_heap =
-      pmd.GetAllocatorDump("foobar_allocator", MemoryAllocatorDump::kRootHeap);
+      pmd.GetAllocatorDump("foobar_allocator");
   ASSERT_NE(nullptr, root_heap);
-  EXPECT_EQ("foobar_allocator", root_heap->allocator_name());
-  EXPECT_EQ("", root_heap->heap_name());
-  EXPECT_NE("", root_heap->GetAbsoluteName());
-  EXPECT_EQ(4096u, root_heap->physical_size_in_bytes());
-  EXPECT_EQ(42u, root_heap->allocated_objects_count());
-  EXPECT_EQ(1000u, root_heap->allocated_objects_size_in_bytes());
-
-  // Check the extra attributes of |root_heap|.
-  EXPECT_EQ(1234, root_heap->GetIntegerAttribute("attr1"));
-  EXPECT_EQ(99, root_heap->GetIntegerAttribute("attr2"));
+  EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
+  CheckAttribute(root_heap, MemoryAllocatorDump::kNameOuterSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 4096);
+  CheckAttribute(root_heap, MemoryAllocatorDump::kNameInnerSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 1000);
+  CheckAttribute(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsObjects, 42);
+  CheckAttribute(root_heap, "attr1", MemoryAllocatorDump::kTypeScalar, "units1",
+                 1234);
+  CheckAttribute(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
+                 "string_value");
 
   const MemoryAllocatorDump* sub_heap =
-      pmd.GetAllocatorDump("foobar_allocator", "sub_heap");
+      pmd.GetAllocatorDump("foobar_allocator/sub_heap");
   ASSERT_NE(nullptr, sub_heap);
-  EXPECT_EQ("foobar_allocator", sub_heap->allocator_name());
-  EXPECT_EQ("sub_heap", sub_heap->heap_name());
-  EXPECT_NE("", sub_heap->GetAbsoluteName());
-  EXPECT_EQ(1u, sub_heap->physical_size_in_bytes());
-  EXPECT_EQ(2u, sub_heap->allocated_objects_count());
-  EXPECT_EQ(3u, sub_heap->allocated_objects_size_in_bytes());
+  EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
+  CheckAttribute(sub_heap, MemoryAllocatorDump::kNameOuterSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 1);
+  CheckAttribute(sub_heap, MemoryAllocatorDump::kNameInnerSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 2);
+  CheckAttribute(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsObjects, 3);
 
   const MemoryAllocatorDump* empty_sub_heap =
-      pmd.GetAllocatorDump("foobar_allocator", "sub_heap/empty");
+      pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
   ASSERT_NE(nullptr, empty_sub_heap);
-  EXPECT_EQ("foobar_allocator", empty_sub_heap->allocator_name());
-  EXPECT_EQ("sub_heap/empty", empty_sub_heap->heap_name());
-  EXPECT_NE("", sub_heap->GetAbsoluteName());
-  EXPECT_EQ(0u, empty_sub_heap->physical_size_in_bytes());
-  EXPECT_EQ(0u, empty_sub_heap->allocated_objects_count());
-  EXPECT_EQ(0u, empty_sub_heap->allocated_objects_size_in_bytes());
+  EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
+  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameOuterSize, nullptr,
+                                   nullptr, nullptr));
+  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameInnerSize, nullptr,
+                                   nullptr, nullptr));
+  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameObjectsCount,
+                                   nullptr, nullptr, nullptr));
 
   // Check that the AsValueInfo doesn't hit any DCHECK.
   scoped_refptr<TracedValue> traced_value(new TracedValue());
@@ -102,13 +139,11 @@
 TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
   FakeMemoryAllocatorDumpProvider fmadp;
   ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
-  pmd.CreateAllocatorDump("foo_allocator", MemoryAllocatorDump::kRootHeap);
-  pmd.CreateAllocatorDump("bar_allocator", "heap");
-  ASSERT_DEATH(
-      pmd.CreateAllocatorDump("foo_allocator", MemoryAllocatorDump::kRootHeap),
-      "");
-  ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator", "heap"), "");
-  ASSERT_DEATH(pmd.CreateAllocatorDump("", "must_have_allocator_name"), "");
+  pmd.CreateAllocatorDump("foo_allocator");
+  pmd.CreateAllocatorDump("bar_allocator/heap");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
 }
 #endif
 
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 859e8e0..1e4d822 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -12,12 +12,22 @@
 #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 "build/build_config.h"
+
+#if !defined(OS_NACL)
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+#endif
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 #include "base/trace_event/malloc_dump_provider.h"
 #include "base/trace_event/process_memory_maps_dump_provider.h"
-#include "base/trace_event/process_memory_totals_dump_provider.h"
-#elif defined(OS_WIN)
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/trace_event/java_heap_dump_provider_android.h"
+#endif
+
+#if defined(OS_WIN)
 #include "base/trace_event/winheap_dump_provider_win.h"
 #endif
 
@@ -144,8 +154,7 @@
 }
 
 MemoryDumpManager::MemoryDumpManager()
-    : dump_provider_currently_active_(nullptr),
-      delegate_(nullptr),
+    : delegate_(nullptr),
       memory_tracing_enabled_(0),
       skip_core_dumpers_auto_registration_for_testing_(false) {
   g_next_guid.GetNext();  // Make sure that first guid is not zero.
@@ -162,12 +171,21 @@
   if (skip_core_dumpers_auto_registration_for_testing_)
     return;
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
   // Enable the core dump providers.
+#if !defined(OS_NACL)
   RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
   RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
   RegisterDumpProvider(MallocDumpProvider::GetInstance());
-#elif defined(OS_WIN)
+#endif
+
+#if defined(OS_ANDROID)
+  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_WIN)
   RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
 #endif
 }
@@ -178,30 +196,41 @@
   delegate_ = delegate;
 }
 
-void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+void MemoryDumpManager::RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+  MemoryDumpProviderInfo mdp_info(task_runner);
   AutoLock lock(lock_);
-  dump_providers_registered_.insert(mdp);
+  dump_providers_.insert(std::make_pair(mdp, mdp_info));
+}
+
+void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+  RegisterDumpProvider(mdp, nullptr);
 }
 
 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
   AutoLock lock(lock_);
 
+  auto it = dump_providers_.find(mdp);
+  if (it == 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
-  // and DumpInto() at the same time).
+  // and OnMemoryDump() at the same time).
   // Otherwise, it is not possible to guarantee that its unregistration is
   // race-free. If you hit this DCHECK, your MDP has a bug.
   DCHECK_IMPLIES(
       subtle::NoBarrier_Load(&memory_tracing_enabled_),
-      mdp->task_runner() && mdp->task_runner()->BelongsToCurrentThread())
-      << "The MemoryDumpProvider " << mdp->GetFriendlyName() << " attempted to "
-      << "unregister itself in a racy way. Please file a crbug.";
+      mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
+      << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
+      << " Please file a crbug.";
 
   // Remove from the enabled providers list. This is to deal with the case that
   // UnregisterDumpProvider is called while the trace is enabled.
-  dump_providers_enabled_.erase(mdp);
-  dump_providers_registered_.erase(mdp);
+  dump_providers_.erase(it);
 }
 
 void MemoryDumpManager::RequestGlobalDump(
@@ -244,25 +273,26 @@
   ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
   bool did_any_provider_dump = false;
 
-  // Iterate over the active dump providers and invoke DumpInto(pmd).
+  // 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.DumpInto() call). This is to simplify the clients' design
+  // 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 DumpInto() invocation can happen:
+  // 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.
   {
     AutoLock lock(lock_);
-    for (auto dump_provider_iter = dump_providers_enabled_.begin();
-         dump_provider_iter != dump_providers_enabled_.end();) {
-      // InvokeDumpProviderLocked will remove the MDP from the set if it fails.
-      MemoryDumpProvider* mdp = *dump_provider_iter;
-      ++dump_provider_iter;
-      if (mdp->task_runner()) {
-        // The DumpInto() call must be posted.
-        bool did_post_async_task = mdp->task_runner()->PostTask(
+    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.
@@ -282,27 +312,24 @@
     FinalizeDumpAndAddToTrace(pmd_holder);
 }
 
-// Invokes the MemoryDumpProvider.DumpInto(), taking care of the failsafe logic
-// which disables the dumper when failing (crbug.com/461788).
+// 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();
-  dump_provider_currently_active_ = mdp;
-  bool dump_successful = mdp->DumpInto(pmd);
-  dump_provider_currently_active_ = nullptr;
+  bool dump_successful = mdp->OnMemoryDump(pmd);
   if (!dump_successful) {
-    LOG(ERROR) << "The memory dumper " << mdp->GetFriendlyName()
-               << " failed, possibly due to sandboxing (crbug.com/461788), "
-                  "disabling it for current process. Try restarting chrome "
-                  "with the --no-sandbox switch.";
-    dump_providers_enabled_.erase(mdp);
+    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;
   }
   return dump_successful;
 }
 
 // This is posted to arbitrary threads as a continuation of CreateProcessDump(),
-// when one or more MemoryDumpProvider(s) require the DumpInto() call to happen
-// on a different thread.
+// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
+// happen on a different thread.
 void MemoryDumpManager::ContinueAsyncProcessDump(
     MemoryDumpProvider* mdp,
     scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
@@ -316,7 +343,7 @@
 
     // Check if the MemoryDumpProvider is still there. It might have been
     // destroyed and unregistered while hopping threads.
-    if (dump_providers_enabled_.count(mdp))
+    if (dump_providers_.count(mdp))
       InvokeDumpProviderLocked(mdp, pmd);
 
     // Finalize the dump appending it to the trace if this was the last
@@ -341,18 +368,16 @@
 
   // There is no point starting the tracing without a delegate.
   if (!enabled || !delegate_) {
-    dump_providers_enabled_.clear();
+    // Disable all the providers.
+    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+      it->second.disabled = true;
     return;
   }
 
-  // Merge the dictionary of allocator attributes from all dump providers
-  // into the session state.
   session_state_ = new MemoryDumpSessionState();
-  for (const MemoryDumpProvider* mdp : dump_providers_registered_) {
-    session_state_->allocators_attributes_type_info.Update(
-        mdp->allocator_attributes_type_info());
-  }
-  dump_providers_enabled_ = dump_providers_registered_;
+  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+    it->second.disabled = false;
+
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
 
   if (delegate_->IsCoordinatorProcess()) {
@@ -365,10 +390,16 @@
 void MemoryDumpManager::OnTraceLogDisabled() {
   AutoLock lock(lock_);
   periodic_dump_timer_.Stop();
-  dump_providers_enabled_.clear();
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
   session_state_ = nullptr;
 }
 
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner(task_runner), disabled(false) {
+}
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 371a47a..3645ac1 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -17,6 +17,9 @@
 #include "base/trace_event/trace_event.h"
 
 namespace base {
+
+class SingleThreadTaskRunner;
+
 namespace trace_event {
 
 namespace {
@@ -46,6 +49,12 @@
 
   // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
   // expected to either be a singleton or unregister itself.
+  // If the optional |task_runner| argument is non-null, all the calls to the
+  // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
+  // able to handle calls on arbitrary threads.
+  void RegisterDumpProvider(
+      MemoryDumpProvider* mdp,
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
   void RegisterDumpProvider(MemoryDumpProvider* mdp);
   void UnregisterDumpProvider(MemoryDumpProvider* mdp);
 
@@ -65,12 +74,6 @@
   void OnTraceLogEnabled() override;
   void OnTraceLogDisabled() override;
 
-  // Returns the MemoryDumpProvider which is currently being dumping into a
-  // ProcessMemoryDump via DumpInto(...) if any, nullptr otherwise.
-  MemoryDumpProvider* dump_provider_currently_active() const {
-    return dump_provider_currently_active_;
-  }
-
   // Returns the MemoryDumpSessionState object, which is shared by all the
   // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
   // session lifetime.
@@ -79,6 +82,17 @@
   }
 
  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;
@@ -102,11 +116,7 @@
       MemoryDumpProvider* mdp,
       scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
 
-  hash_set<MemoryDumpProvider*> dump_providers_registered_;  // Not owned.
-  hash_set<MemoryDumpProvider*> dump_providers_enabled_;     // Not owned.
-
-  // TODO(primiano): this is required only until crbug.com/466121 gets fixed.
-  MemoryDumpProvider* dump_provider_currently_active_;  // Not owned.
+  hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
 
   // Shared among all the PMDs to keep state scoped to the tracing session.
   scoped_refptr<MemoryDumpSessionState> session_state_;
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 589c406..1da9429 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -81,44 +81,35 @@
 
 class MockDumpProvider : public MemoryDumpProvider {
  public:
-  MockDumpProvider() {}
+  MockDumpProvider() : last_session_state_(nullptr) {}
 
+  // Ctor used by the RespectTaskRunnerAffinity test.
   explicit MockDumpProvider(
       const scoped_refptr<SingleThreadTaskRunner>& task_runner)
-      : MemoryDumpProvider(task_runner) {}
+      : last_session_state_(nullptr), task_runner_(task_runner) {}
 
-  // Ctor for the SharedSessionState test.
-  explicit MockDumpProvider(const std::string& id) {
-    DeclareAllocatorAttribute("allocator" + id, "attr" + id, "type" + id);
-  }
+  virtual ~MockDumpProvider() {}
 
-  MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd));
+  MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));
 
-  // DumpInto() override for the ActiveDumpProviderConsistency test.
-  bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) {
-    EXPECT_EQ(
-        this,
-        MemoryDumpManager::GetInstance()->dump_provider_currently_active());
+  // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
+  bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
+    EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
     return true;
   }
 
-  // DumpInto() override for the RespectTaskRunnerAffinity test.
-  bool DumpIntoAndCheckTaskRunner(ProcessMemoryDump* pmd) {
-    EXPECT_TRUE(task_runner()->RunsTasksOnCurrentThread());
+  // OnMemoryDump() override for the SharedSessionState test.
+  bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
+    MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
+    if (last_session_state_)
+      EXPECT_EQ(last_session_state_, cur_session_state);
+    last_session_state_ = cur_session_state;
     return true;
   }
 
-  // DumpInto() override for the SharedSessionState test.
-  bool DumpIntoAndCheckSessionState(ProcessMemoryDump* pmd) {
-    EXPECT_TRUE(pmd->session_state());
-    const auto& attrs_type_info =
-        pmd->session_state()->allocators_attributes_type_info;
-    EXPECT_TRUE(attrs_type_info.Exists("allocator1", "attr1"));
-    EXPECT_TRUE(attrs_type_info.Exists("allocator2", "attr2"));
-    return true;
-  }
-
-  const char* GetFriendlyName() const override { return "MockDumpProvider"; }
+ private:
+  MemoryDumpSessionState* last_session_state_;
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
 };
 
 TEST_F(MemoryDumpManagerTest, SingleDumper) {
@@ -127,14 +118,14 @@
 
   // Check that the dumper is not called if the memory category is not enabled.
   EnableTracing("foo-and-bar-but-not-memory");
-  EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
   // Now repeat enabling the memory category and check that the dumper is
   // invoked this time.
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp, DumpInto(_)).Times(3).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
   for (int i = 0; i < 3; ++i)
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
@@ -143,22 +134,26 @@
 
   // Finally check the unregister logic (no calls to the mdp after unregister).
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp, DumpInto(_)).Times(0);
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   TraceLog::GetInstance()->SetDisabled();
 }
 
 TEST_F(MemoryDumpManagerTest, SharedSessionState) {
-  MockDumpProvider mdp1("1");  // Will declare an allocator property "attr1".
-  MockDumpProvider mdp2("2");  // Will declare an allocator property "attr2".
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
   mdm_->RegisterDumpProvider(&mdp1);
   mdm_->RegisterDumpProvider(&mdp2);
 
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp1, DumpInto(_)).Times(2).WillRepeatedly(
-      Invoke(&mdp1, &MockDumpProvider::DumpIntoAndCheckSessionState));
-  EXPECT_CALL(mdp2, DumpInto(_)).Times(2).WillRepeatedly(
-      Invoke(&mdp2, &MockDumpProvider::DumpIntoAndCheckSessionState));
+  EXPECT_CALL(mdp1, OnMemoryDump(_))
+      .Times(2)
+      .WillRepeatedly(
+          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .Times(2)
+      .WillRepeatedly(
+          Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
 
   for (int i = 0; i < 2; ++i)
     mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
@@ -173,8 +168,8 @@
   // Enable only mdp1.
   mdm_->RegisterDumpProvider(&mdp1);
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
-  EXPECT_CALL(mdp2, DumpInto(_)).Times(0);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
@@ -182,16 +177,16 @@
   mdm_->UnregisterDumpProvider(&mdp1);
   mdm_->RegisterDumpProvider(&mdp2);
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
-  EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 
   // Enable both mdp1 and mdp2.
   mdm_->RegisterDumpProvider(&mdp1);
   EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
-  EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
   DisableTracing();
 }
@@ -214,11 +209,11 @@
     threads.back()->Start();
     mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
     MockDumpProvider* mdp = mdps.back();
-    mdm_->RegisterDumpProvider(mdp);
-    EXPECT_CALL(*mdp, DumpInto(_))
+    mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
+    EXPECT_CALL(*mdp, OnMemoryDump(_))
         .Times(i)
         .WillRepeatedly(
-            Invoke(mdp, &MockDumpProvider::DumpIntoAndCheckTaskRunner));
+            Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
   }
 
   EnableTracing(kTraceCategory);
@@ -266,41 +261,16 @@
   mdm_->RegisterDumpProvider(&mdp2);
   EnableTracing(kTraceCategory);
 
-  EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
-  EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
+  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, DumpInto(_)).Times(0);
-  EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
   mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
 
   DisableTracing();
 }
 
-// TODO(primiano): remove once crbug.com/466121 gets fixed.
-// Ascertains that calls to MDM::dump_provider_currently_active() actually
-// returns the MemoryDumpProvider currently active during the DumpInto() call.
-TEST_F(MemoryDumpManagerTest, ActiveDumpProviderConsistency) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
-
-  mdm_->RegisterDumpProvider(&mdp1);
-  mdm_->RegisterDumpProvider(&mdp2);
-  EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp1, DumpInto(_))
-      .Times(2)
-      .WillRepeatedly(Invoke(
-          &mdp1,
-          &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
-  EXPECT_CALL(mdp2, DumpInto(_))
-      .Times(2)
-      .WillRepeatedly(Invoke(
-          &mdp2,
-          &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
-  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
-  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
-  DisableTracing();
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_dump_provider.cc b/base/trace_event/memory_dump_provider.cc
deleted file mode 100644
index a2d3889..0000000
--- a/base/trace_event/memory_dump_provider.cc
+++ /dev/null
@@ -1,32 +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.
-
-#include "base/trace_event/memory_dump_provider.h"
-
-#include "base/single_thread_task_runner.h"
-
-namespace base {
-namespace trace_event {
-
-MemoryDumpProvider::MemoryDumpProvider() {
-}
-
-MemoryDumpProvider::MemoryDumpProvider(
-    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
-    : task_runner_(task_runner) {
-}
-
-MemoryDumpProvider::~MemoryDumpProvider() {
-}
-
-void MemoryDumpProvider::DeclareAllocatorAttribute(
-    const std::string& allocator_name,
-    const std::string& attribute_name,
-    const std::string& attribute_type) {
-  allocator_attributes_type_info_.Set(
-      allocator_name, attribute_name, attribute_type);
-}
-
-}  // namespace trace_event
-}  // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 9ec7ad9..6e6551c 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -6,13 +6,9 @@
 #define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
 
 #include "base/base_export.h"
-#include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
+#include "base/macros.h"
 
 namespace base {
-
-class SingleThreadTaskRunner;
-
 namespace trace_event {
 
 class ProcessMemoryDump;
@@ -21,45 +17,15 @@
 class BASE_EXPORT MemoryDumpProvider {
  public:
   // Called by the MemoryDumpManager when generating memory dumps.
-  // Returns: true if the |pmd| was successfully populated, false otherwise.
-  virtual bool DumpInto(ProcessMemoryDump* pmd) = 0;
-
-  virtual const char* GetFriendlyName() const = 0;
-
-  const MemoryAllocatorAttributesTypeInfo& allocator_attributes_type_info()
-      const {
-    return allocator_attributes_type_info_;
-  }
-
-  // The dump provider can specify an optional thread affinity (in its
-  // base constructor call). If |task_runner| is non empty, all the calls to
-  // DumpInto are guaranteed to be posted to that TaskRunner.
-  const scoped_refptr<SingleThreadTaskRunner>& task_runner() const {
-    return task_runner_;
-  }
+  // The embedder should return true if the |pmd| was successfully populated,
+  // false if something went wrong and the dump should be considered invalid.
+  // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
+  // MemoryDumpProvider for the entire trace session if it fails consistently).
+  virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
 
  protected:
-  // Default ctor: the MDP is not bound to any thread (must be a singleton).
-  MemoryDumpProvider();
-
-  // Use this ctor to ensure that DumpInto() is called always on the same thread
-  // specified by |task_runner|.
-  explicit MemoryDumpProvider(
-      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
-
-  virtual ~MemoryDumpProvider();
-
-  void DeclareAllocatorAttribute(const std::string& allocator_name,
-                                 const std::string& attribute_name,
-                                 const std::string& attribute_type);
-
- private:
-  // A map of attributes types (declared through DeclareAllocatorAttribute())
-  // emitted by this allocator dumper.
-  MemoryAllocatorAttributesTypeInfo allocator_attributes_type_info_;
-
-  // (Optional) TaskRunner on which the DumpInfo call should be posted.
-  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+  MemoryDumpProvider() {}
+  virtual ~MemoryDumpProvider() {}
 
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
 };
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
index 38a6fe2..cf29b85 100644
--- a/base/trace_event/memory_dump_session_state.h
+++ b/base/trace_event/memory_dump_session_state.h
@@ -9,16 +9,16 @@
 
 #include "base/base_export.h"
 #include "base/memory/ref_counted.h"
-#include "base/trace_event/memory_allocator_attributes_type_info.h"
 
 namespace base {
 namespace trace_event {
 
+// Container for state variables that should be shared across all the memory
+// dumps in a tracing session.
 class BASE_EXPORT MemoryDumpSessionState
     : public RefCountedThreadSafe<MemoryDumpSessionState> {
  public:
   MemoryDumpSessionState();
-  MemoryAllocatorAttributesTypeInfo allocators_attributes_type_info;
 
  private:
   friend class RefCountedThreadSafe<MemoryDumpSessionState>;
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 836d6ae..54fcad6 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -21,21 +21,17 @@
 }
 
 MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
-    const std::string& allocator_name,
-    const std::string& heap_name) {
-  MemoryAllocatorDump* mad =
-      new MemoryAllocatorDump(allocator_name, heap_name, this);
-  DCHECK_EQ(0ul, allocator_dumps_.count(mad->GetAbsoluteName()));
+    const std::string& absolute_name) {
+  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this);
+  DCHECK_EQ(0ul, allocator_dumps_.count(absolute_name));
   allocator_dumps_storage_.push_back(mad);
-  allocator_dumps_[mad->GetAbsoluteName()] = mad;
+  allocator_dumps_[absolute_name] = mad;
   return mad;
 }
 
 MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
-    const std::string& allocator_name,
-    const std::string& heap_name) const {
-  auto it = allocator_dumps_.find(
-      MemoryAllocatorDump::GetAbsoluteName(allocator_name, heap_name));
+    const std::string& absolute_name) const {
+  auto it = allocator_dumps_.find(absolute_name);
   return it == allocator_dumps_.end() ? nullptr : it->second;
 }
 
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index bd9c543..889356d 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -52,24 +52,16 @@
   // Creates a new MemoryAllocatorDump with the given name and returns the
   // empty object back to the caller.
   // Arguments:
-  //   allocator_name: a name that univocally identifies allocator dumps
-  //     produced by this provider. It acts as a type w.r.t. the allocator
-  //     attributes, in the sense that all the MAD with the same allocator_name
-  //     are expected to have the same attributes.
-  //   heap_name, either:
-  //     - kRootHeap: if the allocator has only one default heap.
-  //     - a string identifing a heap name (e.g., isolate1, isolate2 ...). It is
-  //       possible to specify nesting by using a path-like string (e.g.,
-  //       isolate1/heap_spaceX, isolate1/heap_spaceY, isolate2/heap_spaceX).
-  // The tuple (|allocator_name|, |heap_name|) is unique inside a PMD.
+  //   absolute_name: a name that uniquely identifies allocator dumps produced
+  //       by this provider. It is possible to specify nesting by using a
+  //       path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
+  //       Leading or trailing slashes are not allowed.
   // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
-  MemoryAllocatorDump* CreateAllocatorDump(const std::string& allocator_name,
-                                           const std::string& heap_name);
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
 
   // Looks up a MemoryAllocatorDump given its allocator and heap names, or
   // nullptr if not found.
-  MemoryAllocatorDump* GetAllocatorDump(const std::string& allocator_name,
-                                        const std::string& heap_name) const;
+  MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
 
   // Returns the map of the MemoryAllocatorDumps added to this dump.
   const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index d728bd3..680fa29 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -15,10 +15,6 @@
 namespace base {
 namespace trace_event {
 
-namespace {
-const char kDumperFriendlyName[] = "ProcessMemoryMaps";
-}
-
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 // static
 std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
@@ -167,7 +163,7 @@
 
 // Called at trace dump point time. Creates a snapshot the memory maps for the
 // current process.
-bool ProcessMemoryMapsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
   uint32 res = 0;
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
@@ -189,9 +185,5 @@
   return false;
 }
 
-const char* ProcessMemoryMapsDumpProvider::GetFriendlyName() const {
-  return kDumperFriendlyName;
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
index 0d30db2..c73c4d2 100644
--- a/base/trace_event/process_memory_maps_dump_provider.h
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -20,8 +20,7 @@
   static ProcessMemoryMapsDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool DumpInto(ProcessMemoryDump* pmd) override;
-  const char* GetFriendlyName() const override;
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index 2ce2504..e45d30a 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -118,21 +118,21 @@
   std::ifstream non_existent_file("/tmp/does-not-exist");
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
   CHECK_EQ(false, non_existent_file.good());
-  pmmdp->DumpInto(&pmd_invalid);
+  pmmdp->OnMemoryDump(&pmd_invalid);
   ASSERT_FALSE(pmd_invalid.has_process_mmaps());
 
   // Emulate an empty /proc/self/smaps.
   std::ifstream empty_file("/dev/null");
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
   CHECK_EQ(true, empty_file.good());
-  pmmdp->DumpInto(&pmd_invalid);
+  pmmdp->OnMemoryDump(&pmd_invalid);
   ASSERT_FALSE(pmd_invalid.has_process_mmaps());
 
   // Parse the 1st smaps file.
   ProcessMemoryDump pmd_1(nullptr /* session_state */);
   std::istringstream test_smaps_1(kTestSmaps1);
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
-  pmmdp->DumpInto(&pmd_1);
+  pmmdp->OnMemoryDump(&pmd_1);
   ASSERT_TRUE(pmd_1.has_process_mmaps());
   const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
   ASSERT_EQ(2UL, regions_1.size());
@@ -157,7 +157,7 @@
   ProcessMemoryDump pmd_2(nullptr /* session_state */);
   std::istringstream test_smaps_2(kTestSmaps2);
   ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
-  pmmdp->DumpInto(&pmd_2);
+  pmmdp->OnMemoryDump(&pmd_2);
   ASSERT_TRUE(pmd_2.has_process_mmaps());
   const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
   ASSERT_EQ(1UL, regions_2.size());
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
index 125be38..06b537c 100644
--- a/base/trace_event/process_memory_totals_dump_provider.cc
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -16,8 +16,6 @@
 
 namespace {
 
-const char kDumperFriendlyName[] = "ProcessMemoryTotals";
-
 ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
 #if !defined(OS_MACOSX) || defined(OS_IOS)
   return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
@@ -44,7 +42,7 @@
 
 // Called at trace dump point time. Creates a snapshot the memory counters for
 // the current process.
-bool ProcessMemoryTotalsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
   const uint64 rss_bytes = rss_bytes_for_testing
                                ? rss_bytes_for_testing
                                : process_metrics_->GetWorkingSetSize();
@@ -58,9 +56,5 @@
   return false;
 }
 
-const char* ProcessMemoryTotalsDumpProvider::GetFriendlyName() const {
-  return kDumperFriendlyName;
-}
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
index 8dae966..6c86eb6 100644
--- a/base/trace_event/process_memory_totals_dump_provider.h
+++ b/base/trace_event/process_memory_totals_dump_provider.h
@@ -22,8 +22,7 @@
   static ProcessMemoryTotalsDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool DumpInto(ProcessMemoryDump* pmd) override;
-  const char* GetFriendlyName() const override;
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
index ffaf177..f9bb6c0 100644
--- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -17,13 +17,13 @@
   scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
 
   ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
-  pmtdp->DumpInto(pmd_before.get());
+  pmtdp->OnMemoryDump(pmd_before.get());
 
   // Pretend that the RSS of the process increased of +1M.
   const size_t kAllocSize = 1048576;
   ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
 
-  pmtdp->DumpInto(pmd_after.get());
+  pmtdp->OnMemoryDump(pmd_after.get());
 
   ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
 
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 9bbd172..9a072e4 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -6,13 +6,10 @@
     'trace_event_sources' : [
       'trace_event/java_heap_dump_provider_android.cc',
       'trace_event/java_heap_dump_provider_android.h',
-      'trace_event/memory_allocator_attributes_type_info.cc',
-      'trace_event/memory_allocator_attributes_type_info.h',
       'trace_event/memory_allocator_dump.cc',
       'trace_event/memory_allocator_dump.h',
       'trace_event/memory_dump_manager.cc',
       'trace_event/memory_dump_manager.h',
-      'trace_event/memory_dump_provider.cc',
       'trace_event/memory_dump_provider.h',
       'trace_event/memory_dump_request_args.h',
       'trace_event/memory_dump_session_state.cc',
@@ -56,7 +53,7 @@
       }],
     ],
     'trace_event_test_sources' : [
-      'trace_event/memory_allocator_attributes_type_info_unittest.cc',
+      'trace_event/java_heap_dump_provider_android_unittest.cc',
       'trace_event/memory_allocator_dump_unittest.cc',
       'trace_event/memory_dump_manager_unittest.cc',
       'trace_event/process_memory_maps_dump_provider_unittest.cc',
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index e0249f5..86f959f 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -709,6 +709,13 @@
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
         arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
+        id, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, \
+        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
 // Records a single NESTABLE_ASYNC_END event called "name" immediately, with 2
 // associated arguments. If the category is not enabled, then this does nothing.
 #define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
@@ -716,6 +723,13 @@
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
         arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
+        id, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+        category_group, name, id, \
+        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
 // Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
 // with 2 associated arguments. If the category is not enabled, then this
 // does nothing.
@@ -1081,6 +1095,7 @@
 #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_SCOPE_MASK   (static_cast<unsigned char>( \
     TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index bcba436..26bd0c7 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -114,7 +114,7 @@
   Thread end_chrome_tracing_thread("end_chrome_tracing");
   WaitableEvent complete_event(false, false);
   end_chrome_tracing_thread.Start();
-  end_chrome_tracing_thread.message_loop()->PostTask(
+  end_chrome_tracing_thread.task_runner()->PostTask(
       FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this),
                             Unretained(&complete_event)));
   complete_event.Wait();
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index cbeeeab..5ae7fb2 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -14,8 +14,8 @@
 #include "base/format_macros.h"
 #include "base/json/string_escape.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
 #include "base/process/process_metrics.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -28,6 +28,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/sys_info.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/worker_pool.h"
@@ -741,6 +742,11 @@
     StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
   }
 
+  // Output async tts marker field if flag is set.
+  if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
+    StringAppendF(out, ", \"use_async_tts\":1");
+  }
+
   // If id_ is set, print it out as a hex string so we don't loose any
   // bits (it might be a 64-bit pointer).
   if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
@@ -1406,7 +1412,7 @@
     AutoLock lock(lock_);
 
     // Can't enable tracing when Flush() is in progress.
-    DCHECK(!flush_message_loop_proxy_.get());
+    DCHECK(!flush_task_runner_);
 
     InternalTraceOptions new_options =
         GetInternalOptionsFromTraceOptions(options);
@@ -1680,9 +1686,9 @@
 }
 
 // Flush() works as the following:
-// 1. Flush() is called in threadA whose message loop is saved in
-//    flush_message_loop_proxy_;
-// 2. If thread_message_loops_ is not empty, threadA posts task to each message
+// 1. Flush() is called in thread A whose task runner is saved in
+//    flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
 //    loop to flush the thread local buffers; otherwise finish the flush;
 // 3. FlushCurrentThread() deletes the thread local event buffer:
 //    - The last batch of events of the thread are flushed into the main buffer;
@@ -1710,9 +1716,11 @@
       thread_message_loop_task_runners;
   {
     AutoLock lock(lock_);
-    DCHECK(!flush_message_loop_proxy_.get());
-    flush_message_loop_proxy_ = MessageLoopProxy::current();
-    DCHECK(!thread_message_loops_.size() || flush_message_loop_proxy_.get());
+    DCHECK(!flush_task_runner_);
+    flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+                             ? ThreadTaskRunnerHandle::Get()
+                             : nullptr;
+    DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
     flush_output_callback_ = cb;
 
     if (thread_shared_chunk_) {
@@ -1735,7 +1743,7 @@
           FROM_HERE,
           Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
     }
-    flush_message_loop_proxy_->PostDelayedTask(
+    flush_task_runner_->PostDelayedTask(
         FROM_HERE,
         Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
         TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
@@ -1789,7 +1797,7 @@
     UseNextTraceBuffer();
     thread_message_loops_.clear();
 
-    flush_message_loop_proxy_ = NULL;
+    flush_task_runner_ = NULL;
     flush_output_callback = flush_output_callback_;
     flush_output_callback_.Reset();
   }
@@ -1812,7 +1820,7 @@
 void TraceLog::FlushCurrentThread(int generation) {
   {
     AutoLock lock(lock_);
-    if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get()) {
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
       // This is late. The corresponding flush has finished.
       return;
     }
@@ -1822,19 +1830,18 @@
   delete thread_local_event_buffer_.Get();
 
   AutoLock lock(lock_);
-  if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get() ||
+  if (!CheckGeneration(generation) || !flush_task_runner_ ||
       thread_message_loops_.size())
     return;
 
-  flush_message_loop_proxy_->PostTask(
-      FROM_HERE,
-      Bind(&TraceLog::FinishFlush, Unretained(this), generation));
+  flush_task_runner_->PostTask(
+      FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
 }
 
 void TraceLog::OnFlushTimeout(int generation) {
   {
     AutoLock lock(lock_);
-    if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get()) {
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
       // Flush has finished before timeout.
       return;
     }
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 33a85c9..50d33ca 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -18,6 +18,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
@@ -798,8 +799,8 @@
   ThreadLocalBoolean thread_is_in_trace_event_;
 
   // Contains the message loops of threads that have had at least one event
-  // added into the local event buffer. Not using MessageLoopProxy because we
-  // need to know the life time of the message loops.
+  // added into the local event buffer. Not using SingleThreadTaskRunner
+  // because we need to know the life time of the message loops.
   hash_set<MessageLoop*> thread_message_loops_;
 
   // For events which can't be added into the thread local buffer, e.g. events
@@ -809,7 +810,7 @@
 
   // Set when asynchronous Flush is in progress.
   OutputCallback flush_output_callback_;
-  scoped_refptr<MessageLoopProxy> flush_message_loop_proxy_;
+  scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
   subtle::AtomicWord generation_;
   bool use_worker_thread_;
 
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
index 2bf6d38..ab8ba0d 100644
--- a/base/trace_event/trace_event_memory.cc
+++ b/base/trace_event/trace_event_memory.cc
@@ -6,9 +6,10 @@
 
 #include "base/debug/leak_annotations.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_local_storage.h"
@@ -144,11 +145,11 @@
 //////////////////////////////////////////////////////////////////////////////
 
 TraceMemoryController::TraceMemoryController(
-    scoped_refptr<MessageLoopProxy> message_loop_proxy,
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
     HeapProfilerStartFunction heap_profiler_start_function,
     HeapProfilerStopFunction heap_profiler_stop_function,
     GetHeapProfileFunction get_heap_profile_function)
-    : message_loop_proxy_(message_loop_proxy),
+    : task_runner_(task_runner.Pass()),
       heap_profiler_start_function_(heap_profiler_start_function),
       heap_profiler_stop_function_(heap_profiler_stop_function),
       get_heap_profile_function_(get_heap_profile_function),
@@ -174,10 +175,9 @@
   if (!enabled)
     return;
   DVLOG(1) << "OnTraceLogEnabled";
-  message_loop_proxy_->PostTask(
-      FROM_HERE,
-      base::Bind(&TraceMemoryController::StartProfiling,
-                 weak_factory_.GetWeakPtr()));
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&TraceMemoryController::StartProfiling,
+                                    weak_factory_.GetWeakPtr()));
 }
 
 void TraceMemoryController::OnTraceLogDisabled() {
@@ -185,10 +185,9 @@
   // called, so we cannot tell if it was enabled before. Always try to turn
   // off profiling.
   DVLOG(1) << "OnTraceLogDisabled";
-  message_loop_proxy_->PostTask(
-      FROM_HERE,
-      base::Bind(&TraceMemoryController::StopProfiling,
-                 weak_factory_.GetWeakPtr()));
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&TraceMemoryController::StopProfiling,
+                                    weak_factory_.GetWeakPtr()));
 }
 
 void TraceMemoryController::StartProfiling() {
diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h
index 8e70020..e2b3ae9 100644
--- a/base/trace_event/trace_event_memory.h
+++ b/base/trace_event/trace_event_memory.h
@@ -20,7 +20,7 @@
 
 namespace base {
 
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 
 namespace trace_event {
 
@@ -35,15 +35,14 @@
   typedef void (*HeapProfilerStopFunction)();
   typedef char* (*GetHeapProfileFunction)();
 
-  // |message_loop_proxy| must be a proxy to the primary thread for the client
+  // |task_runner| must be a task runner for the primary thread for the client
   // process, e.g. the UI thread in a browser. The function pointers must be
   // pointers to tcmalloc heap profiling functions; by avoiding direct calls to
   // these functions we avoid a dependency on third_party/tcmalloc from base.
-  TraceMemoryController(
-      scoped_refptr<MessageLoopProxy> message_loop_proxy,
-      HeapProfilerStartFunction heap_profiler_start_function,
-      HeapProfilerStopFunction heap_profiler_stop_function,
-      GetHeapProfileFunction get_heap_profile_function);
+  TraceMemoryController(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                        HeapProfilerStartFunction heap_profiler_start_function,
+                        HeapProfilerStopFunction heap_profiler_stop_function,
+                        GetHeapProfileFunction get_heap_profile_function);
   virtual ~TraceMemoryController();
 
   // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
@@ -65,7 +64,7 @@
   bool IsTimerRunningForTest() const;
 
   // Ensures the observer starts and stops tracing on the primary thread.
-  scoped_refptr<MessageLoopProxy> message_loop_proxy_;
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
 
   // Pointers to tcmalloc heap profiling functions. Allows this class to use
   // tcmalloc functions without introducing a dependency from base to tcmalloc.
diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc
index 4732733..781a054 100644
--- a/base/trace_event/trace_event_memory_unittest.cc
+++ b/base/trace_event/trace_event_memory_unittest.cc
@@ -7,7 +7,6 @@
 #include <sstream>
 #include <string>
 
-#include "base/message_loop/message_loop.h"
 #include "base/trace_event/trace_event_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,12 +39,9 @@
   EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
 
   // Creating a controller adds it to the TraceLog observer list.
-  scoped_ptr<TraceMemoryController> controller(
-      new TraceMemoryController(
-          message_loop.message_loop_proxy(),
-          ::HeapProfilerWithPseudoStackStart,
-          ::HeapProfilerStop,
-          ::GetHeapProfile));
+  scoped_ptr<TraceMemoryController> controller(new TraceMemoryController(
+      message_loop.task_runner(), ::HeapProfilerWithPseudoStackStart,
+      ::HeapProfilerStop, ::GetHeapProfile));
   EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
   EXPECT_TRUE(
       TraceLog::GetInstance()->HasEnabledStateObserver(controller.get()));
diff --git a/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
index 995f53b..03dff59 100644
--- a/base/trace_event/trace_event_system_stats_monitor_unittest.cc
+++ b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -7,7 +7,6 @@
 #include <sstream>
 #include <string>
 
-#include "base/message_loop/message_loop.h"
 #include "base/trace_event/trace_event_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -36,8 +35,7 @@
 
   // Creating a system stats monitor adds it to the TraceLog observer list.
   scoped_ptr<TraceEventSystemStatsMonitor> system_stats_monitor(
-      new TraceEventSystemStatsMonitor(
-          message_loop.message_loop_proxy()));
+      new TraceEventSystemStatsMonitor(message_loop.task_runner()));
   EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
   EXPECT_TRUE(
       TraceLog::GetInstance()->HasEnabledStateObserver(
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 0d3b091..17953e7 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -9,10 +9,12 @@
 #include "base/command_line.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
+#include "base/location.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
@@ -95,10 +97,9 @@
     WaitableEvent flush_complete_event(false, false);
     Thread flush_thread("flush");
     flush_thread.Start();
-    flush_thread.message_loop()->PostTask(FROM_HERE,
-      base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
-                 base::Unretained(this),
-                 &flush_complete_event));
+    flush_thread.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
+                              base::Unretained(this), &flush_complete_event));
     flush_complete_event.Wait();
   }
 
@@ -1424,7 +1425,7 @@
   WaitableEvent task_complete_event(false, false);
   thread.Start();
 
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event));
   task_complete_event.Wait();
   thread.Stop();
@@ -1445,9 +1446,9 @@
     threads[i] = new Thread(StringPrintf("Thread %d", i));
     task_complete_events[i] = new WaitableEvent(false, false);
     threads[i]->Start();
-    threads[i]->message_loop()->PostTask(
-        FROM_HERE, base::Bind(&TraceManyInstantEvents,
-                              i, num_events, task_complete_events[i]));
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents, i, num_events,
+                              task_complete_events[i]));
   }
 
   for (int i = 0; i < num_threads; i++) {
@@ -1493,9 +1494,9 @@
     task_complete_events[i] = new WaitableEvent(false, false);
     threads[i]->Start();
     thread_ids[i] = threads[i]->thread_id();
-    threads[i]->message_loop()->PostTask(
-        FROM_HERE, base::Bind(&TraceManyInstantEvents,
-                              i, kNumEvents, task_complete_events[i]));
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
+                              task_complete_events[i]));
   }
   for (int i = 0; i < kNumThreads; i++) {
     task_complete_events[i]->Wait();
@@ -2725,17 +2726,17 @@
   Thread thread("1");
   WaitableEvent task_complete_event(false, false);
   thread.Start();
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&TraceLog::SetCurrentThreadBlocksMessageLoop,
                       Unretained(TraceLog::GetInstance())));
 
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
   task_complete_event.Wait();
 
   WaitableEvent task_start_event(false, false);
   WaitableEvent task_stop_event(false, false);
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
   task_start_event.Wait();
 
@@ -2796,15 +2797,15 @@
   WaitableEvent task_complete_event(false, false);
   thread.Start();
 
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
   task_complete_event.Wait();
 
   WaitableEvent task_start_event(false, false);
   WaitableEvent task_stop_event(false, false);
-  thread.message_loop()->PostTask(
-      FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped,
-                      &task_start_event, &task_stop_event));
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped, &task_start_event,
+                      &task_stop_event));
   task_start_event.Wait();
 
   EndTraceAndFlush();
@@ -2821,14 +2822,14 @@
   WaitableEvent task_complete_event(false, false);
   thread.Start();
 
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
   task_complete_event.Wait();
   task_complete_event.Reset();
 
   WaitableEvent task_start_event(false, false);
   WaitableEvent task_stop_event(false, false);
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
   task_start_event.Wait();
 
@@ -2843,7 +2844,7 @@
   // executed in the thread before continuing.
   task_start_event.Reset();
   task_stop_event.Reset();
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
   task_start_event.Wait();
   task_stop_event.Signal();
@@ -2852,7 +2853,7 @@
   // TraceLog should discover the generation mismatch and recover the thread
   // local buffer for the thread without any error.
   BeginTrace();
-  thread.message_loop()->PostTask(
+  thread.task_runner()->PostTask(
       FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
   task_complete_event.Wait();
   task_complete_event.Reset();
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
index 3a4fd87..e1e9bcf 100644
--- a/base/trace_event/winheap_dump_provider_win.cc
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -13,21 +13,21 @@
 
 namespace {
 
-const char kDumperFriendlyName[] = "winheap";
-
 // Report a heap dump to a process memory dump. The |heap_info| structure
-// contains the information about this heap, and |heap_name| will be used to
-// represent it in the report.
+// contains the information about this heap, and |dump_absolute_name| will be
+// used to represent it in the report.
 bool ReportHeapDump(ProcessMemoryDump* pmd,
                     const WinHeapInfo& heap_info,
-                    const std::string& heap_name) {
-  MemoryAllocatorDump* dump =
-      pmd->CreateAllocatorDump(kDumperFriendlyName, heap_name);
+                    const std::string& dump_absolute_name) {
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_absolute_name);
   if (!dump)
     return false;
-  dump->set_physical_size_in_bytes(heap_info.committed_size);
-  dump->set_allocated_objects_count(heap_info.block_count);
-  dump->set_allocated_objects_size_in_bytes(heap_info.allocated_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                  MemoryAllocatorDump::kUnitsBytes, heap_info.committed_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                  MemoryAllocatorDump::kUnitsBytes, heap_info.allocated_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                  MemoryAllocatorDump::kUnitsObjects, heap_info.block_count);
   return true;
 }
 
@@ -38,7 +38,7 @@
                    LeakySingletonTraits<WinHeapDumpProvider>>::get();
 }
 
-bool WinHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+bool WinHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
   // Retrieves the number of heaps in the current process.
   DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
   WinHeapInfo all_heap_info = {0};
@@ -68,16 +68,12 @@
     all_heap_info.block_count += heap_info.block_count;
   }
   // Report the heap dump.
-  if (!ReportHeapDump(pmd, all_heap_info, MemoryAllocatorDump::kRootHeap))
+  if (!ReportHeapDump(pmd, all_heap_info, "winheap"))
     return false;
 
   return true;
 }
 
-const char* WinHeapDumpProvider::GetFriendlyName() const {
-  return kDumperFriendlyName;
-}
-
 bool WinHeapDumpProvider::GetHeapInformation(
     WinHeapInfo* heap_info,
     const std::set<void*>& block_to_skip) {
diff --git a/base/trace_event/winheap_dump_provider_win.h b/base/trace_event/winheap_dump_provider_win.h
index 8abac47..99239a0 100644
--- a/base/trace_event/winheap_dump_provider_win.h
+++ b/base/trace_event/winheap_dump_provider_win.h
@@ -29,8 +29,7 @@
   static WinHeapDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool DumpInto(ProcessMemoryDump* pmd) override;
-  const char* GetFriendlyName() const override;
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
diff --git a/base/trace_event/winheap_dump_provider_win_unittest.cc b/base/trace_event/winheap_dump_provider_win_unittest.cc
index 99da18a..2309802 100644
--- a/base/trace_event/winheap_dump_provider_win_unittest.cc
+++ b/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -13,14 +13,14 @@
 namespace base {
 namespace trace_event {
 
-TEST(WinHeapDumpProviderTest, DumpInto) {
+TEST(WinHeapDumpProviderTest, OnMemoryDump) {
   ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
 
   WinHeapDumpProvider* winheap_dump_provider =
       WinHeapDumpProvider::GetInstance();
   ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
 
-  ASSERT_TRUE(winheap_dump_provider->DumpInto(&pmd));
+  ASSERT_TRUE(winheap_dump_provider->OnMemoryDump(&pmd));
 }
 
 }  // namespace trace_event
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index a60e260..9029f4f 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -28,19 +28,13 @@
 namespace tracked_objects {
 
 namespace {
-// TODO(jar): Evaluate the perf impact of enabling this.  If the perf impact is
-// negligible, enable by default.
-// Flag to compile out parent-child link recording.
-const bool kTrackParentChildLinks = false;
-
 // When ThreadData is first initialized, should we start in an ACTIVE state to
 // record all of the startup-time tasks, or should we start up DEACTIVATED, so
 // that we only record after parsing the command line flag --enable-tracking.
 // Note that the flag may force either state, so this really controls only the
-// period of time up until that flag is parsed. If there is no flag seen, then
+// period of time up until that flag is parsed.  If there is no flag seen, then
 // this state may prevail for much or all of the process lifetime.
-const ThreadData::Status kInitialStartupState =
-    ThreadData::PROFILING_CHILDREN_ACTIVE;
+const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE;
 
 // Control whether an alternate time source (Now() function) is supported by
 // the ThreadData class.  This compile time flag should be set to true if we
@@ -61,9 +55,10 @@
 // State of the profiler timing enabledness.
 base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING;
 
-// Returns whether profiler timing is enabled. The default is true, but this may
-// be overridden by a command-line flag. Some platforms may programmatically set
-// this command-line flag to the "off" value if it's not specified.
+// Returns whether profiler timing is enabled.  The default is true, but this
+// may be overridden by a command-line flag.  Some platforms may
+// programmatically set this command-line flag to the "off" value if it's not
+// specified.
 // This in turn can be overridden by explicitly calling
 // ThreadData::EnableProfilerTiming, say, based on a field trial.
 inline bool IsProfilerTimingEnabled() {
@@ -92,13 +87,40 @@
 //------------------------------------------------------------------------------
 // DeathData tallies durations when a death takes place.
 
-DeathData::DeathData() {
-  Clear();
+DeathData::DeathData()
+    : count_(0),
+      sample_probability_count_(0),
+      run_duration_sum_(0),
+      queue_duration_sum_(0),
+      run_duration_max_(0),
+      queue_duration_max_(0),
+      run_duration_sample_(0),
+      queue_duration_sample_(0),
+      last_phase_snapshot_(nullptr) {
 }
 
-DeathData::DeathData(int count) {
-  Clear();
-  count_ = count;
+DeathData::DeathData(const DeathData& other)
+    : count_(other.count_),
+      sample_probability_count_(other.sample_probability_count_),
+      run_duration_sum_(other.run_duration_sum_),
+      queue_duration_sum_(other.queue_duration_sum_),
+      run_duration_max_(other.run_duration_max_),
+      queue_duration_max_(other.queue_duration_max_),
+      run_duration_sample_(other.run_duration_sample_),
+      queue_duration_sample_(other.queue_duration_sample_),
+      last_phase_snapshot_(nullptr) {
+  // This constructor will be used by std::map when adding new DeathData values
+  // to the map.  At that point, last_phase_snapshot_ is still NULL, so we don't
+  // need to worry about ownership transfer.
+  DCHECK(other.last_phase_snapshot_ == nullptr);
+}
+
+DeathData::~DeathData() {
+  while (last_phase_snapshot_) {
+    const DeathDataPhaseSnapshot* snapshot = last_phase_snapshot_;
+    last_phase_snapshot_ = snapshot->prev;
+    delete snapshot;
+  }
 }
 
 // TODO(jar): I need to see if this macro to optimize branching is worth using.
@@ -117,6 +139,12 @@
   // We'll just clamp at INT_MAX, but we should note this in the UI as such.
   if (count_ < INT_MAX)
     ++count_;
+
+  int sample_probability_count = sample_probability_count_;
+  if (sample_probability_count < INT_MAX)
+    ++sample_probability_count;
+  sample_probability_count_ = sample_probability_count;
+
   queue_duration_sum_ += queue_duration;
   run_duration_sum_ += run_duration;
 
@@ -125,14 +153,16 @@
   if (run_duration_max_ < run_duration)
     run_duration_max_ = run_duration;
 
-  // Take a uniformly distributed sample over all durations ever supplied.
-  // The probability that we (instead) use this new sample is 1/count_.  This
-  // results in a completely uniform selection of the sample (at least when we
-  // don't clamp count_... but that should be inconsequentially likely).
-  // We ignore the fact that we correlated our selection of a sample to the run
-  // and queue times (i.e., we used them to generate random_number).
-  CHECK_GT(count_, 0);
-  if (0 == (random_number % count_)) {
+  // Take a uniformly distributed sample over all durations ever supplied during
+  // the current profiling phase.
+  // The probability that we (instead) use this new sample is
+  // 1/sample_probability_count_. This results in a completely uniform selection
+  // of the sample (at least when we don't clamp sample_probability_count_...
+  // but that should be inconsequentially likely).  We ignore the fact that we
+  // correlated our selection of a sample to the run and queue times (i.e., we
+  // used them to generate random_number).
+  CHECK_GT(sample_probability_count, 0);
+  if (0 == (random_number % sample_probability_count)) {
     queue_duration_sample_ = queue_duration;
     run_duration_sample_ = run_duration;
   }
@@ -160,14 +190,43 @@
   return queue_duration_sample_;
 }
 
-void DeathData::Clear() {
-  count_ = 0;
-  run_duration_sum_ = 0;
+const DeathDataPhaseSnapshot* DeathData::last_phase_snapshot() const {
+  return last_phase_snapshot_;
+}
+
+void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
+  // Snapshotting and storing current state.
+  last_phase_snapshot_ = new DeathDataPhaseSnapshot(
+      profiling_phase, count_, run_duration_sum_, run_duration_max_,
+      run_duration_sample_, queue_duration_sum_, queue_duration_max_,
+      queue_duration_sample_, last_phase_snapshot_);
+
+  // Not touching fields for which a delta can be computed by comparing with a
+  // snapshot from the previous phase. Resetting other fields.  Sample values
+  // will be reset upon next death recording because sample_probability_count_
+  // is set to 0.
+  // We avoid resetting to 0 in favor of deltas whenever possible.  The reason
+  // is that for incrementable fields, resetting to 0 from the snapshot thread
+  // potentially in parallel with incrementing in the death thread may result in
+  // significant data corruption that has a potential to grow with time.  Not
+  // resetting incrementable fields and using deltas will cause any
+  // off-by-little corruptions to be likely fixed at the next snapshot.
+  // The max values are not incrementable, and cannot be deduced using deltas
+  // for a given phase. Hence, we have to reset them to 0.  But the potential
+  // damage is limited to getting the previous phase's max to apply for the next
+  // phase, and the error doesn't have a potential to keep growing with new
+  // resets.
+  // sample_probability_count_ is incrementable, but must be reset to 0 at the
+  // phase end, so that we start a new uniformly randomized sample selection
+  // after the reset.  Corruptions due to race conditions are possible, but the
+  // damage is limited to selecting a wrong sample, which is not something that
+  // can cause accumulating or cascading effects.
+  // If there were no corruptions caused by race conditions, we never send a
+  // sample for the previous phase in the next phase's snapshot because
+  // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count.
+  sample_probability_count_ = 0;
   run_duration_max_ = 0;
-  run_duration_sample_ = 0;
-  queue_duration_sum_ = 0;
   queue_duration_max_ = 0;
-  queue_duration_sample_ = 0;
 }
 
 //------------------------------------------------------------------------------
@@ -181,20 +240,34 @@
       queue_duration_sample(-1) {
 }
 
-DeathDataSnapshot::DeathDataSnapshot(
-    const tracked_objects::DeathData& death_data)
-    : count(death_data.count()),
-      run_duration_sum(death_data.run_duration_sum()),
-      run_duration_max(death_data.run_duration_max()),
-      run_duration_sample(death_data.run_duration_sample()),
-      queue_duration_sum(death_data.queue_duration_sum()),
-      queue_duration_max(death_data.queue_duration_max()),
-      queue_duration_sample(death_data.queue_duration_sample()) {
+DeathDataSnapshot::DeathDataSnapshot(int count,
+                                     int32 run_duration_sum,
+                                     int32 run_duration_max,
+                                     int32 run_duration_sample,
+                                     int32 queue_duration_sum,
+                                     int32 queue_duration_max,
+                                     int32 queue_duration_sample)
+    : count(count),
+      run_duration_sum(run_duration_sum),
+      run_duration_max(run_duration_max),
+      run_duration_sample(run_duration_sample),
+      queue_duration_sum(queue_duration_sum),
+      queue_duration_max(queue_duration_max),
+      queue_duration_sample(queue_duration_sample) {
 }
 
 DeathDataSnapshot::~DeathDataSnapshot() {
 }
 
+DeathDataSnapshot DeathDataSnapshot::Delta(
+    const DeathDataSnapshot& older) const {
+  return DeathDataSnapshot(count - older.count,
+                           run_duration_sum - older.run_duration_sum,
+                           run_duration_max, run_duration_sample,
+                           queue_duration_sum - older.queue_duration_sum,
+                           queue_duration_max, queue_duration_sample);
+}
+
 //------------------------------------------------------------------------------
 BirthOnThread::BirthOnThread(const Location& location,
                              const ThreadData& current)
@@ -206,8 +279,7 @@
 BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
 }
 
-BirthOnThreadSnapshot::BirthOnThreadSnapshot(
-    const tracked_objects::BirthOnThread& birth)
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth)
     : location(birth.location()),
       thread_name(birth.birth_thread()->thread_name()) {
 }
@@ -238,9 +310,9 @@
 // static
 bool ThreadData::now_function_is_time_ = false;
 
-// A TLS slot which points to the ThreadData instance for the current thread. We
-// do a fake initialization here (zeroing out data), and then the real in-place
-// construction happens when we call tls_index_.Initialize().
+// A TLS slot which points to the ThreadData instance for the current thread.
+// We do a fake initialization here (zeroing out data), and then the real
+// in-place construction happens when we call tls_index_.Initialize().
 // static
 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
 
@@ -288,7 +360,8 @@
   PushToHeadOfList();  // Which sets real incarnation_count_for_pool_.
 }
 
-ThreadData::~ThreadData() {}
+ThreadData::~ThreadData() {
+}
 
 void ThreadData::PushToHeadOfList() {
   // Toss in a hint of randomness (atop the uniniitalized value).
@@ -361,7 +434,7 @@
 // static
 void ThreadData::OnThreadTermination(void* thread_data) {
   DCHECK(thread_data);  // TLS should *never* call us with a NULL.
-  // We must NOT do any allocations during this callback. There is a chance
+  // We must NOT do any allocations during this callback.  There is a chance
   // that the allocator is no longer active on this thread.
   reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
 }
@@ -385,9 +458,54 @@
 }
 
 // static
-void ThreadData::Snapshot(ProcessDataSnapshot* process_data_snapshot) {
-  ThreadData::SnapshotCurrentPhase(
-      &process_data_snapshot->phased_process_data_snapshots[0]);
+void ThreadData::Snapshot(int current_profiling_phase,
+                          ProcessDataSnapshot* process_data_snapshot) {
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Gather data serially.
+  // This hackish approach *can* get some slightly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  If a user
+  // sees any strangeness, they can always just run their stats gathering a
+  // second time.
+  BirthCountMap birth_counts;
+  for (ThreadData* thread_data = my_list; thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->SnapshotExecutedTasks(current_profiling_phase,
+                                       &process_data_snapshot->phased_snapshots,
+                                       &birth_counts);
+  }
+
+  // Add births that are still active -- i.e. objects that have tallied a birth,
+  // but have not yet tallied a matching death, and hence must be either
+  // running, queued up, or being held in limbo for future posting.
+  auto* current_phase_tasks =
+      &process_data_snapshot->phased_snapshots[current_profiling_phase].tasks;
+  for (const auto& birth_count : birth_counts) {
+    if (birth_count.second > 0) {
+      current_phase_tasks->push_back(
+          TaskSnapshot(BirthOnThreadSnapshot(*birth_count.first),
+                       DeathDataSnapshot(birth_count.second, 0, 0, 0, 0, 0, 0),
+                       "Still_Alive"));
+    }
+  }
+}
+
+// static
+void ThreadData::OnProfilingPhaseCompleted(int profiling_phase) {
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Add snapshots for all instances of death data in all threads serially.
+  // This hackish approach *can* get some slightly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  Any corruption
+  // shouldn't cause "cascading damage" to anything else (in later phases).
+  for (ThreadData* thread_data = my_list; thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->OnProfilingPhaseCompletedOnThread(profiling_phase);
+  }
 }
 
 Births* ThreadData::TallyABirth(const Location& location) {
@@ -404,22 +522,10 @@
     birth_map_[location] = child;
   }
 
-  if (kTrackParentChildLinks && status_ > PROFILING_ACTIVE &&
-      !parent_stack_.empty()) {
-    const Births* parent = parent_stack_.top();
-    ParentChildPair pair(parent, child);
-    if (parent_child_set_.find(pair) == parent_child_set_.end()) {
-      // Lock since the map may get relocated now, and other threads sometimes
-      // snapshot it (but they lock before copying it).
-      base::AutoLock lock(map_lock_);
-      parent_child_set_.insert(pair);
-    }
-  }
-
   return child;
 }
 
-void ThreadData::TallyADeath(const Births& birth,
+void ThreadData::TallyADeath(const Births& births,
                              int32 queue_duration,
                              const TaskStopwatch& stopwatch) {
   int32 run_duration = stopwatch.RunDurationMs();
@@ -428,9 +534,9 @@
   const uint32 kSomePrimeNumber = 2147483647;
   random_number_ += queue_duration + run_duration + kSomePrimeNumber;
   // An address is going to have some randomness to it as well ;-).
-  random_number_ ^= static_cast<uint32>(&birth - reinterpret_cast<Births*>(0));
+  random_number_ ^= static_cast<uint32>(&births - reinterpret_cast<Births*>(0));
 
-  // We don't have queue durations without OS timer. OS timer is automatically
+  // We don't have queue durations without OS timer.  OS timer is automatically
   // used for task-post-timing, so the use of an alternate timer implies all
   // queue times are invalid, unless it was explicitly said that we can trust
   // the alternate timer.
@@ -440,22 +546,15 @@
     queue_duration = 0;
   }
 
-  DeathMap::iterator it = death_map_.find(&birth);
+  DeathMap::iterator it = death_map_.find(&births);
   DeathData* death_data;
   if (it != death_map_.end()) {
     death_data = &it->second;
   } else {
     base::AutoLock lock(map_lock_);  // Lock as the map may get relocated now.
-    death_data = &death_map_[&birth];
+    death_data = &death_map_[&births];
   }  // Release lock ASAP.
   death_data->RecordDeath(queue_duration, run_duration, random_number_);
-
-  if (!kTrackParentChildLinks)
-    return;
-  if (!parent_stack_.empty()) {  // We might get turned off.
-    DCHECK_EQ(parent_stack_.top(), &birth);
-    parent_stack_.pop();
-  }
 }
 
 // static
@@ -475,8 +574,8 @@
   // Even if we have been DEACTIVATED, we will process any pending births so
   // that our data structures (which counted the outstanding births) remain
   // consistent.
-  const Births* birth = completed_task.birth_tally;
-  if (!birth)
+  const Births* births = completed_task.birth_tally;
+  if (!births)
     return;
   ThreadData* current_thread_data = stopwatch.GetThreadData();
   if (!current_thread_data)
@@ -485,7 +584,7 @@
   // Watch out for a race where status_ is changing, and hence one or both
   // of start_of_run or end_of_run is zero.  In that case, we didn't bother to
   // get a time value since we "weren't tracking" and we were trying to be
-  // efficient by not calling for a genuine time value. For simplicity, we'll
+  // efficient by not calling for a genuine time value.  For simplicity, we'll
   // use a default zero duration when we can't calculate a true value.
   TrackedTime start_of_run = stopwatch.StartTime();
   int32 queue_duration = 0;
@@ -493,18 +592,18 @@
     queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
         .InMilliseconds();
   }
-  current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
 }
 
 // static
 void ThreadData::TallyRunOnWorkerThreadIfTracking(
-    const Births* birth,
+    const Births* births,
     const TrackedTime& time_posted,
     const TaskStopwatch& stopwatch) {
   // Even if we have been DEACTIVATED, we will process any pending births so
   // that our data structures (which counted the outstanding births) remain
   // consistent.
-  if (!birth)
+  if (!births)
     return;
 
   // TODO(jar): Support the option to coalesce all worker-thread activity under
@@ -512,7 +611,7 @@
   // reduce memory (making it provably bounded), but run incrementally slower
   // (since we'll use locks on TallyABirth and TallyADeath).  The good news is
   // that the locks on TallyADeath will be *after* the worker thread has run,
-  // and hence nothing will be waiting for the completion (... besides some
+  // and hence nothing will be waiting for the completion (...  besides some
   // other thread that might like to run).  Also, the worker threads tasks are
   // generally longer, and hence the cost of the lock may perchance be amortized
   // over the long task's lifetime.
@@ -525,17 +624,17 @@
   if (!start_of_run.is_null()) {
     queue_duration = (start_of_run - time_posted).InMilliseconds();
   }
-  current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
 }
 
 // static
 void ThreadData::TallyRunInAScopedRegionIfTracking(
-    const Births* birth,
+    const Births* births,
     const TaskStopwatch& stopwatch) {
   // Even if we have been DEACTIVATED, we will process any pending births so
   // that our data structures (which counted the outstanding births) remain
   // consistent.
-  if (!birth)
+  if (!births)
     return;
 
   ThreadData* current_thread_data = stopwatch.GetThreadData();
@@ -543,93 +642,74 @@
     return;
 
   int32 queue_duration = 0;
-  current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
-}
-
-// static
-void ThreadData::SnapshotAllExecutedTasks(
-    ProcessDataPhaseSnapshot* process_data_phase,
-    BirthCountMap* birth_counts) {
-  // Get an unchanging copy of a ThreadData list.
-  ThreadData* my_list = ThreadData::first();
-
-  // Gather data serially.
-  // This hackish approach *can* get some slighly corrupt tallies, as we are
-  // grabbing values without the protection of a lock, but it has the advantage
-  // of working even with threads that don't have message loops.  If a user
-  // sees any strangeness, they can always just run their stats gathering a
-  // second time.
-  for (ThreadData* thread_data = my_list;
-       thread_data;
-       thread_data = thread_data->next()) {
-    thread_data->SnapshotExecutedTasks(process_data_phase, birth_counts);
-  }
-}
-
-// static
-void ThreadData::SnapshotCurrentPhase(
-    ProcessDataPhaseSnapshot* process_data_phase) {
-  // Add births that have run to completion to |collected_data|.
-  // |birth_counts| tracks the total number of births recorded at each location
-  // for which we have not seen a death count.
-  BirthCountMap birth_counts;
-  ThreadData::SnapshotAllExecutedTasks(process_data_phase, &birth_counts);
-
-  // Add births that are still active -- i.e. objects that have tallied a birth,
-  // but have not yet tallied a matching death, and hence must be either
-  // running, queued up, or being held in limbo for future posting.
-  for (const auto& birth_count : birth_counts) {
-    if (birth_count.second > 0) {
-      process_data_phase->tasks.push_back(TaskSnapshot(
-          *birth_count.first, DeathData(birth_count.second), "Still_Alive"));
-    }
-  }
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
 }
 
 void ThreadData::SnapshotExecutedTasks(
-    ProcessDataPhaseSnapshot* process_data_phase,
+    int current_profiling_phase,
+    PhasedProcessDataSnapshotMap* phased_snapshots,
     BirthCountMap* birth_counts) {
   // Get copy of data, so that the data will not change during the iterations
   // and processing.
-  ThreadData::BirthMap birth_map;
-  ThreadData::DeathMap death_map;
-  ThreadData::ParentChildSet parent_child_set;
-  SnapshotMaps(&birth_map, &death_map, &parent_child_set);
-
-  for (const auto& death : death_map) {
-    process_data_phase->tasks.push_back(
-        TaskSnapshot(*death.first, death.second, thread_name()));
-    (*birth_counts)[death.first] -= death.first->birth_count();
-  }
+  BirthMap birth_map;
+  DeathsSnapshot deaths;
+  SnapshotMaps(current_profiling_phase, &birth_map, &deaths);
 
   for (const auto& birth : birth_map) {
     (*birth_counts)[birth.second] += birth.second->birth_count();
   }
 
-  if (!kTrackParentChildLinks)
-    return;
+  for (const auto& death : deaths) {
+    (*birth_counts)[death.first] -= death.first->birth_count();
 
-  for (const auto& parent_child : parent_child_set) {
-    process_data_phase->descendants.push_back(
-        ParentChildPairSnapshot(parent_child));
+    // For the current death data, walk through all its snapshots, starting from
+    // the current one, then from the previous profiling phase etc., and for
+    // each snapshot calculate the delta between the snapshot and the previous
+    // phase, if any.  Store the deltas in the result.
+    for (const DeathDataPhaseSnapshot* phase = &death.second; phase;
+         phase = phase->prev) {
+      const DeathDataSnapshot& death_data =
+          phase->prev ? phase->death_data.Delta(phase->prev->death_data)
+                      : phase->death_data;
+
+      if (death_data.count > 0) {
+        (*phased_snapshots)[phase->profiling_phase].tasks.push_back(
+            TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data,
+                         thread_name()));
+      }
+    }
   }
 }
 
 // This may be called from another thread.
-void ThreadData::SnapshotMaps(BirthMap* birth_map,
-                              DeathMap* death_map,
-                              ParentChildSet* parent_child_set) {
+void ThreadData::SnapshotMaps(int profiling_phase,
+                              BirthMap* birth_map,
+                              DeathsSnapshot* deaths) {
   base::AutoLock lock(map_lock_);
+
   for (const auto& birth : birth_map_)
     (*birth_map)[birth.first] = birth.second;
-  for (const auto& death : death_map_)
-    (*death_map)[death.first] = death.second;
 
-  if (!kTrackParentChildLinks)
-    return;
+  for (const auto& death : death_map_) {
+    deaths->push_back(std::make_pair(
+        death.first,
+        DeathDataPhaseSnapshot(profiling_phase, death.second.count(),
+                               death.second.run_duration_sum(),
+                               death.second.run_duration_max(),
+                               death.second.run_duration_sample(),
+                               death.second.queue_duration_sum(),
+                               death.second.queue_duration_max(),
+                               death.second.queue_duration_sample(),
+                               death.second.last_phase_snapshot())));
+  }
+}
 
-  for (const auto& parent_child : parent_child_set_)
-    parent_child_set->insert(parent_child);
+void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) {
+  base::AutoLock lock(map_lock_);
+
+  for (auto& death : death_map_) {
+    death.second.OnProfilingPhaseCompleted(profiling_phase);
+  }
 }
 
 static void OptionallyInitializeAlternateTimer() {
@@ -674,13 +754,10 @@
   // never again change in this process.
   ++incarnation_counter_;
 
-  // The lock is not critical for setting status_, but it doesn't hurt. It also
+  // The lock is not critical for setting status_, but it doesn't hurt.  It also
   // ensures that if we have a racy initialization, that we'll bail as soon as
   // we get the lock earlier in this method.
   status_ = kInitialStartupState;
-  if (!kTrackParentChildLinks &&
-      kInitialStartupState == PROFILING_CHILDREN_ACTIVE)
-    status_ = PROFILING_ACTIVE;
   DCHECK(status_ != UNINITIALIZED);
   return true;
 }
@@ -688,12 +765,12 @@
 // static
 bool ThreadData::InitializeAndSetTrackingStatus(Status status) {
   DCHECK_GE(status, DEACTIVATED);
-  DCHECK_LE(status, PROFILING_CHILDREN_ACTIVE);
+  DCHECK_LE(status, PROFILING_ACTIVE);
 
   if (!Initialize())  // No-op if already initialized.
     return false;  // Not compiled in.
 
-  if (!kTrackParentChildLinks && status > DEACTIVATED)
+  if (status > DEACTIVATED)
     status = PROFILING_ACTIVE;
   status_ = status;
   return true;
@@ -710,20 +787,6 @@
 }
 
 // static
-bool ThreadData::TrackingParentChildStatus() {
-  return status_ >= PROFILING_CHILDREN_ACTIVE;
-}
-
-// static
-void ThreadData::PrepareForStartOfRun(const Births* parent) {
-  if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) {
-    ThreadData* current_thread_data = Get();
-    if (current_thread_data)
-      current_thread_data->parent_stack_.push(parent);
-  }
-}
-
-// static
 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
   DCHECK(now_function);
   if (kAllowAlternateTimeSourceHandling)
@@ -909,11 +972,37 @@
 }
 
 //------------------------------------------------------------------------------
+// DeathDataPhaseSnapshot
+
+DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
+    int profiling_phase,
+    int count,
+    int32 run_duration_sum,
+    int32 run_duration_max,
+    int32 run_duration_sample,
+    int32 queue_duration_sum,
+    int32 queue_duration_max,
+    int32 queue_duration_sample,
+    const DeathDataPhaseSnapshot* prev)
+    : profiling_phase(profiling_phase),
+      death_data(count,
+                 run_duration_sum,
+                 run_duration_max,
+                 run_duration_sample,
+                 queue_duration_sum,
+                 queue_duration_max,
+                 queue_duration_sample),
+      prev(prev) {
+}
+
+//------------------------------------------------------------------------------
+// TaskSnapshot
+
 TaskSnapshot::TaskSnapshot() {
 }
 
-TaskSnapshot::TaskSnapshot(const BirthOnThread& birth,
-                           const DeathData& death_data,
+TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth,
+                           const DeathDataSnapshot& death_data,
                            const std::string& death_thread_name)
     : birth(birth),
       death_data(death_data),
@@ -924,21 +1013,6 @@
 }
 
 //------------------------------------------------------------------------------
-// ParentChildPairSnapshot
-
-ParentChildPairSnapshot::ParentChildPairSnapshot() {
-}
-
-ParentChildPairSnapshot::ParentChildPairSnapshot(
-    const ThreadData::ParentChildPair& parent_child)
-    : parent(*parent_child.first),
-      child(*parent_child.second) {
-}
-
-ParentChildPairSnapshot::~ParentChildPairSnapshot() {
-}
-
-//------------------------------------------------------------------------------
 // ProcessDataPhaseSnapshot
 
 ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 9643265..cd69fb7 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -22,6 +22,7 @@
 #include "base/profiler/alternate_timer.h"
 #include "base/profiler/tracked_time.h"
 #include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
 #include "base/threading/thread_local_storage.h"
 
 namespace base {
@@ -85,7 +86,7 @@
 // threads there are, and how many Locations of construction there are.
 // Fortunately, we don't use memory that is the product of those two counts, but
 // rather we only need one Births instance for each thread that constructs an
-// instance at a Location. In many cases, instances are only created on one
+// instance at a Location.  In many cases, instances are only created on one
 // thread, so the memory utilization is actually fairly restrained.
 //
 // Lastly, when an instance is deleted, the final tallies of statistics are
@@ -106,14 +107,14 @@
 // Each thread maintains a list of data items specific to that thread in a
 // ThreadData instance (for that specific thread only).  The two critical items
 // are lists of DeathData and Births instances.  These lists are maintained in
-// STL maps, which are indexed by Location. As noted earlier, we can compare
+// STL maps, which are indexed by Location.  As noted earlier, we can compare
 // locations very efficiently as we consider the underlying data (file,
 // function, line) to be atoms, and hence pointer comparison is used rather than
 // (slow) string comparisons.
 //
 // To provide a mechanism for iterating over all "known threads," which means
 // threads that have recorded a birth or a death, we create a singly linked list
-// of ThreadData instances. Each such instance maintains a pointer to the next
+// of ThreadData instances.  Each such instance maintains a pointer to the next
 // one.  A static member of ThreadData provides a pointer to the first item on
 // this global list, and access via that all_thread_data_list_head_ item
 // requires the use of the list_lock_.
@@ -148,14 +149,13 @@
 // TaskSnapshot instances, so that such instances can be sorted and
 // aggregated (and remain frozen during our processing).
 //
-// Profiling consists of phases. The concrete phase in the sequence of phases is
-// identified by its 0-based index.
+// Profiling consists of phases.  The concrete phase in the sequence of phases
+// is identified by its 0-based index.
 //
 // The ProcessDataPhaseSnapshot struct is a serialized representation of the
-// list of ThreadData objects for a process for a concrete profiling phase. It
-// holds a set of TaskSnapshots and tracks parent/child relationships for the
-// executed tasks. The statistics in a snapshot are gathered asynhcronously
-// relative to their ongoing updates.
+// list of ThreadData objects for a process for a concrete profiling phase.  It
+// holds a set of TaskSnapshots.  The statistics in a snapshot are gathered
+// asynhcronously relative to their ongoing updates.
 // It is possible, though highly unlikely, that stats could be incorrectly
 // recorded by this process (all data is held in 32 bit ints, but we are not
 // atomically collecting all data, so we could have count that does not, for
@@ -177,13 +177,6 @@
 // for upload via UMA (where correctness of data may be more significant than
 // for a single screen of about:profiler).
 //
-// TODO(jar): We should support (optionally) the recording of parent-child
-// relationships for tasks.  This should be done by detecting what tasks are
-// Born during the running of a parent task.  The resulting data can be used by
-// a smarter profiler to aggregate the cost of a series of child tasks into
-// the ancestor task.  It can also be used to illuminate what child or parent is
-// related to each task.
-//
 // TODO(jar): We need to store DataCollections, and provide facilities for
 // taking the difference between two gathered DataCollections.  For now, we're
 // just adding a hack that Reset()s to zero all counts and stats.  This is also
@@ -254,64 +247,29 @@
 };
 
 //------------------------------------------------------------------------------
-// Basic info summarizing multiple destructions of a tracked object with a
-// single birthplace (fixed Location).  Used both on specific threads, and also
-// in snapshots when integrating assembled data.
-
-class BASE_EXPORT DeathData {
- public:
-  // Default initializer.
-  DeathData();
-
-  // When deaths have not yet taken place, and we gather data from all the
-  // threads, we create DeathData stats that tally the number of births without
-  // a corresponding death.
-  explicit DeathData(int count);
-
-  // Update stats for a task destruction (death) that had a Run() time of
-  // |duration|, and has had a queueing delay of |queue_duration|.
-  void RecordDeath(const int32 queue_duration,
-                   const int32 run_duration,
-                   const uint32 random_number);
-
-  // Metrics accessors, used only for serialization and in tests.
-  int count() const;
-  int32 run_duration_sum() const;
-  int32 run_duration_max() const;
-  int32 run_duration_sample() const;
-  int32 queue_duration_sum() const;
-  int32 queue_duration_max() const;
-  int32 queue_duration_sample() const;
-
-  // Reset all tallies to zero. This is used as a hack on realtime data.
-  void Clear();
-
- private:
-  // Members are ordered from most regularly read and updated, to least
-  // frequently used.  This might help a bit with cache lines.
-  // Number of runs seen (divisor for calculating averages).
-  int count_;
-  // Basic tallies, used to compute averages.
-  int32 run_duration_sum_;
-  int32 queue_duration_sum_;
-  // Max values, used by local visualization routines.  These are often read,
-  // but rarely updated.
-  int32 run_duration_max_;
-  int32 queue_duration_max_;
-  // Samples, used by crowd sourcing gatherers.  These are almost never read,
-  // and rarely updated.
-  int32 run_duration_sample_;
-  int32 queue_duration_sample_;
-};
-
-//------------------------------------------------------------------------------
 // A "snapshotted" representation of the DeathData class.
 
 struct BASE_EXPORT DeathDataSnapshot {
   DeathDataSnapshot();
-  explicit DeathDataSnapshot(const DeathData& death_data);
+
+  // Constructs the snapshot from individual values.
+  // The alternative would be taking a DeathData parameter, but this would
+  // create a loop since DeathData indirectly refers DeathDataSnapshot.  Passing
+  // a wrapper structure as a param or using an empty constructor for
+  // snapshotting DeathData would be less efficient.
+  DeathDataSnapshot(int count,
+                    int32 run_duration_sum,
+                    int32 run_duration_max,
+                    int32 run_duration_sample,
+                    int32 queue_duration_sum,
+                    int32 queue_duration_max,
+                    int32 queue_duration_sample);
   ~DeathDataSnapshot();
 
+  // Calculates and returns the delta between this snapshot and an earlier
+  // snapshot of the same task |older|.
+  DeathDataSnapshot Delta(const DeathDataSnapshot& older) const;
+
   int count;
   int32 run_duration_sum;
   int32 run_duration_max;
@@ -322,6 +280,107 @@
 };
 
 //------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData for a particular profiling
+// phase.  Used as an element of the list of phase snapshots owned by DeathData.
+
+struct DeathDataPhaseSnapshot {
+  DeathDataPhaseSnapshot(int profiling_phase,
+                         int count,
+                         int32 run_duration_sum,
+                         int32 run_duration_max,
+                         int32 run_duration_sample,
+                         int32 queue_duration_sum,
+                         int32 queue_duration_max,
+                         int32 queue_duration_sample,
+                         const DeathDataPhaseSnapshot* prev);
+
+  // Profiling phase at which completion this snapshot was taken.
+  int profiling_phase;
+
+  // Death data snapshot.
+  DeathDataSnapshot death_data;
+
+  // Pointer to a snapshot from the previous phase.
+  const DeathDataPhaseSnapshot* prev;
+};
+
+//------------------------------------------------------------------------------
+// Information about deaths of a task on a given thread, called "death thread".
+// Access to members of this class is never protected by a lock.  The fields
+// are accessed in such a way that corruptions resulting from race conditions
+// are not significant, and don't accumulate as a result of multiple accesses.
+// All invocations of DeathData::OnProfilingPhaseCompleted and
+// ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process
+// must be called from the same thread. It doesn't matter what thread it is, but
+// it's important the same thread is used as a snapshot thread during the whole
+// process lifetime.  All fields except sample_probability_count_ can be
+// snapshotted.
+
+class BASE_EXPORT DeathData {
+ public:
+  DeathData();
+  DeathData(const DeathData& other);
+  ~DeathData();
+
+  // Update stats for a task destruction (death) that had a Run() time of
+  // |duration|, and has had a queueing delay of |queue_duration|.
+  void RecordDeath(const int32 queue_duration,
+                   const int32 run_duration,
+                   const uint32 random_number);
+
+  // Metrics and past snapshots accessors, used only for serialization and in
+  // tests.
+  int count() const;
+  int32 run_duration_sum() const;
+  int32 run_duration_max() const;
+  int32 run_duration_sample() const;
+  int32 queue_duration_sum() const;
+  int32 queue_duration_max() const;
+  int32 queue_duration_sample() const;
+  const DeathDataPhaseSnapshot* last_phase_snapshot() const;
+
+  // Called when the current profiling phase, identified by |profiling_phase|,
+  // ends.
+  // Must be called only on the snapshot thread.
+  void OnProfilingPhaseCompleted(int profiling_phase);
+
+ private:
+  // Members are ordered from most regularly read and updated, to least
+  // frequently used.  This might help a bit with cache lines.
+  // Number of runs seen (divisor for calculating averages).
+  // Can be incremented only on the death thread.
+  int count_;
+
+  // Count used in determining probability of selecting exec/queue times from a
+  // recorded death as samples.
+  // Gets incremented only on the death thread, but can be set to 0 by
+  // OnProfilingPhaseCompleted() on the snapshot thread.
+  int sample_probability_count_;
+
+  // Basic tallies, used to compute averages.  Can be incremented only on the
+  // death thread.
+  int32 run_duration_sum_;
+  int32 queue_duration_sum_;
+  // Max values, used by local visualization routines.  These are often read,
+  // but rarely updated.  The max values get assigned only on the death thread,
+  // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the
+  // snapshot thread.
+  int32 run_duration_max_;
+  int32 queue_duration_max_;
+  // Samples, used by crowd sourcing gatherers.  These are almost never read,
+  // and rarely updated.  They can be modified only on the death thread.
+  int32 run_duration_sample_;
+  int32 queue_duration_sample_;
+
+  // Snapshot of this death data made at the last profiling phase completion, if
+  // any.  DeathData owns the whole list starting with this pointer.
+  // Can be accessed only on the snapshot thread.
+  const DeathDataPhaseSnapshot* last_phase_snapshot_;
+
+  DISALLOW_ASSIGN(DeathData);
+};
+
+//------------------------------------------------------------------------------
 // A temporary collection of data that can be sorted and summarized.  It is
 // gathered (carefully) from many threads.  Instances are held in arrays and
 // processed, filtered, and rendered.
@@ -330,12 +389,14 @@
 
 struct BASE_EXPORT TaskSnapshot {
   TaskSnapshot();
-  TaskSnapshot(const BirthOnThread& birth,
-               const DeathData& death_data,
+  TaskSnapshot(const BirthOnThreadSnapshot& birth,
+               const DeathDataSnapshot& death_data,
                const std::string& death_thread_name);
   ~TaskSnapshot();
 
   BirthOnThreadSnapshot birth;
+  // Delta between death data for a thread for a certain profiling phase and the
+  // snapshot for the pervious phase, if any.  Otherwise, just a snapshot.
   DeathDataSnapshot death_data;
   std::string death_thread_name;
 };
@@ -361,19 +422,15 @@
   // Current allowable states of the tracking system.  The states can vary
   // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
   enum Status {
-    UNINITIALIZED,              // PRistine, link-time state before running.
-    DORMANT_DURING_TESTS,       // Only used during testing.
-    DEACTIVATED,                // No longer recording profiling.
-    PROFILING_ACTIVE,           // Recording profiles (no parent-child links).
-    PROFILING_CHILDREN_ACTIVE,  // Fully active, recording parent-child links.
-    STATUS_LAST = PROFILING_CHILDREN_ACTIVE
+    UNINITIALIZED,         // Pristine, link-time state before running.
+    DORMANT_DURING_TESTS,  // Only used during testing.
+    DEACTIVATED,           // No longer recording profiling.
+    PROFILING_ACTIVE,      // Recording profiles.
+    STATUS_LAST = PROFILING_ACTIVE
   };
 
   typedef base::hash_map<Location, Births*, Location::Hash> BirthMap;
   typedef std::map<const Births*, DeathData> DeathMap;
-  typedef std::pair<const Births*, const Births*> ParentChildPair;
-  typedef std::set<ParentChildPair> ParentChildSet;
-  typedef std::stack<const Births*> ParentStack;
 
   // Initialize the current thread context with a new instance of ThreadData.
   // This is used by all threads that have names, and should be explicitly
@@ -388,8 +445,21 @@
   static ThreadData* Get();
 
   // Fills |process_data_snapshot| with phased snapshots of all profiling
-  // phases, including the current one.
-  static void Snapshot(ProcessDataSnapshot* process_data_snapshot);
+  // phases, including the current one, identified by |current_profiling_phase|.
+  // |current_profiling_phase| is necessary because a child process can start
+  // after several phase-changing events, so it needs to receive the current
+  // phase number from the browser process to fill the correct entry for the
+  // current phase in the |process_data_snapshot| map.
+  static void Snapshot(int current_profiling_phase,
+                       ProcessDataSnapshot* process_data_snapshot);
+
+  // Called when the current profiling phase, identified by |profiling_phase|,
+  // ends.
+  // |profiling_phase| is necessary because a child process can start after
+  // several phase-changing events, so it needs to receive the phase number from
+  // the browser process to fill the correct entry in the
+  // completed_phases_snapshots_ map.
+  static void OnProfilingPhaseCompleted(int profiling_phase);
 
   // Finds (or creates) a place to count births from the given location in this
   // thread, and increment that tally.
@@ -403,7 +473,7 @@
   // delayed tasks, and it indicates when the task should have run (i.e., when
   // it should have posted out of the timer queue, and into the work queue.
   // The |end_of_run| was just obtained by a call to Now() (just after the task
-  // finished). It is provided as an argument to help with testing.
+  // finished).  It is provided as an argument to help with testing.
   static void TallyRunOnNamedThreadIfTracking(
       const base::TrackingInfo& completed_task,
       const TaskStopwatch& stopwatch);
@@ -415,31 +485,25 @@
   // the task.
   // The |end_of_run| was just obtained by a call to Now() (just after the task
   // finished).
-  static void TallyRunOnWorkerThreadIfTracking(const Births* birth,
+  static void TallyRunOnWorkerThreadIfTracking(const Births* births,
                                                const TrackedTime& time_posted,
                                                const TaskStopwatch& stopwatch);
 
   // Record the end of execution in region, generally corresponding to a scope
   // being exited.
-  static void TallyRunInAScopedRegionIfTracking(const Births* birth,
+  static void TallyRunInAScopedRegionIfTracking(const Births* births,
                                                 const TaskStopwatch& stopwatch);
 
   const std::string& thread_name() const { return thread_name_; }
 
   // Initializes all statics if needed (this initialization call should be made
-  // while we are single threaded). Returns false if unable to initialize.
+  // while we are single threaded).  Returns false if unable to initialize.
   static bool Initialize();
 
   // Sets internal status_.
   // If |status| is false, then status_ is set to DEACTIVATED.
-  // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or
-  // PROFILING_CHILDREN_ACTIVE.
-  // If tracking is not compiled in, this function will return false.
-  // If parent-child tracking is not compiled in, then an attempt to set the
-  // status to PROFILING_CHILDREN_ACTIVE will only result in a status of
-  // PROFILING_ACTIVE (i.e., it can't be set to a higher level than what is
-  // compiled into the binary, and parent-child tracking at the
-  // PROFILING_CHILDREN_ACTIVE level might not be compiled in).
+  // If |status| is true, then status_ is set to PROFILING_ACTIVE.
+  // If it fails to initialize the TLS slot, this function will return false.
   static bool InitializeAndSetTrackingStatus(Status status);
 
   static Status status();
@@ -448,17 +512,6 @@
   // DEACTIVATED).
   static bool TrackingStatus();
 
-  // For testing only, indicate if the status of parent-child tracking is turned
-  // on.  This is currently a compiled option, atop TrackingStatus().
-  static bool TrackingParentChildStatus();
-
-  // Marks a start of a tracked run. It's super fast when tracking is disabled,
-  // and has some internal side effects when we are tracking, so that we can
-  // deduce the amount of time accumulated outside of execution of tracked runs.
-  // The task that will be tracked is passed in as |parent| so that parent-child
-  // relationships can be (optionally) calculated.
-  static void PrepareForStartOfRun(const Births* parent);
-
   // Enables profiler timing.
   static void EnableProfilerTiming();
 
@@ -489,10 +542,12 @@
   friend class TrackedObjectsTest;
   FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown);
   FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown);
-  FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest);
 
   typedef std::map<const BirthOnThread*, int> BirthCountMap;
 
+  typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>>
+      DeathsSnapshot;
+
   // Worker thread construction creates a name since there is none.
   explicit ThreadData(int thread_number);
 
@@ -517,36 +572,31 @@
   Births* TallyABirth(const Location& location);
 
   // Find a place to record a death on this thread.
-  void TallyADeath(const Births& birth,
+  void TallyADeath(const Births& births,
                    int32 queue_duration,
                    const TaskStopwatch& stopwatch);
 
-  // Snapshot (under a lock) the profiled data for the tasks in each ThreadData
-  // instance.  Also updates the |birth_counts| tally for each task to keep
-  // track of the number of living instances of the task.
-  static void SnapshotAllExecutedTasks(
-      ProcessDataPhaseSnapshot* process_data_phase,
-      BirthCountMap* birth_counts);
-
-  // Fills |process_data_phase| with all the recursive results in our process.
-  static void SnapshotCurrentPhase(
-      ProcessDataPhaseSnapshot* process_data_phase);
-
   // Snapshots (under a lock) the profiled data for the tasks for this thread
-  // and writes all of the executed tasks' data -- i.e. the data for the tasks
-  // with with entries in the death_map_ -- into |process_data_phase|.  Also
-  // updates the |birth_counts| tally for each task to keep track of the number
-  // of living instances of the task -- that is, each task maps to the number of
-  // births for the task that have not yet been balanced by a death.
-  void SnapshotExecutedTasks(ProcessDataPhaseSnapshot* process_data_phase,
+  // and writes all of the executed tasks' data -- i.e. the data for all
+  // profiling phases (including the current one: |current_profiling_phase|) for
+  // the tasks with with entries in the death_map_ -- into |phased_snapshots|.
+  // Also updates the |birth_counts| tally for each task to keep track of the
+  // number of living instances of the task -- that is, each task maps to the
+  // number of births for the task that have not yet been balanced by a death.
+  void SnapshotExecutedTasks(int current_profiling_phase,
+                             PhasedProcessDataSnapshotMap* phased_snapshots,
                              BirthCountMap* birth_counts);
 
   // Using our lock, make a copy of the specified maps.  This call may be made
   // on  non-local threads, which necessitate the use of the lock to prevent
   // the map(s) from being reallocated while they are copied.
-  void SnapshotMaps(BirthMap* birth_map,
-                    DeathMap* death_map,
-                    ParentChildSet* parent_child_set);
+  void SnapshotMaps(int profiling_phase,
+                    BirthMap* birth_map,
+                    DeathsSnapshot* deaths);
+
+  // Called for this thread when the current profiling phase, identified by
+  // |profiling_phase|, ends.
+  void OnProfilingPhaseCompletedOnThread(int profiling_phase);
 
   // This method is called by the TLS system when a thread terminates.
   // The argument may be NULL if this thread has never tracked a birth or death.
@@ -578,7 +628,7 @@
   // We use thread local store to identify which ThreadData to interact with.
   static base::ThreadLocalStorage::StaticSlot tls_index_;
 
-  // List of ThreadData instances for use with worker threads. When a worker
+  // List of ThreadData instances for use with worker threads.  When a worker
   // thread is done (terminated), we push it onto this list.  When a new worker
   // thread is created, we first try to re-use a ThreadData instance from the
   // list, and if none are available, construct a new one.
@@ -595,7 +645,7 @@
   static int worker_thread_data_creation_count_;
 
   // The number of times TLS has called us back to cleanup a ThreadData
-  // instance. This is only accessed while list_lock_ is held.
+  // instance.  This is only accessed while list_lock_ is held.
   static int cleanup_count_;
 
   // Incarnation sequence number, indicating how many times (during unittests)
@@ -612,7 +662,7 @@
   // We set status_ to SHUTDOWN when we shut down the tracking service.
   static Status status_;
 
-  // Link to next instance (null terminated list). Used to globally track all
+  // Link to next instance (null terminated list).  Used to globally track all
   // registered instances (corresponds to all registered threads where we keep
   // data).
   ThreadData* next_;
@@ -644,11 +694,6 @@
   // locking before reading it.
   DeathMap death_map_;
 
-  // A set of parents that created children tasks on this thread. Each pair
-  // corresponds to potentially non-local Births (location and thread), and a
-  // local Births (that took place on this thread).
-  ParentChildSet parent_child_set_;
-
   // Lock to protect *some* access to BirthMap and DeathMap.  The maps are
   // regularly read and written on this thread, but may only be read from other
   // threads.  To support this, we acquire this lock if we are writing from this
@@ -657,16 +702,6 @@
   // writing is only done from this thread.
   mutable base::Lock map_lock_;
 
-  // The stack of parents that are currently being profiled. This includes only
-  // tasks that have started a timer recently via PrepareForStartOfRun(), but
-  // not yet concluded with a NowForEndOfRun().  Usually this stack is one deep,
-  // but if a scoped region is profiled, or <sigh> a task runs a nested-message
-  // loop, then the stack can grow larger.  Note that we don't try to deduct
-  // time in nested profiles, as our current timer is based on wall-clock time,
-  // and not CPU time (and we're hopeful that nested timing won't be a
-  // significant additional cost).
-  ParentStack parent_stack_;
-
   // A random number that we used to select decide which sample to keep as a
   // representative sample in each DeathData instance.  We can't start off with
   // much randomness (because we can't call RandInt() on all our threads), so
@@ -688,7 +723,7 @@
 
 //------------------------------------------------------------------------------
 // Stopwatch to measure task run time or simply create a time interval that will
-// be subtracted from the current most nested task's run time. Stopwatches
+// be subtracted from the current most nested task's run time.  Stopwatches
 // coordinate with the stopwatches in which they are nested to avoid
 // double-counting nested tasks run times.
 
@@ -736,32 +771,17 @@
   TaskStopwatch* parent_;
 
 #if DCHECK_IS_ON()
-  // State of the stopwatch. Stopwatch is first constructed in a created state
+  // State of the stopwatch.  Stopwatch is first constructed in a created state
   // state, then is optionally started/stopped, then destructed.
   enum { CREATED, RUNNING, STOPPED } state_;
 
   // Currently running stopwatch that is directly nested in this one, if such
-  // stopwatch exists. NULL otherwise.
+  // stopwatch exists.  NULL otherwise.
   TaskStopwatch* child_;
 #endif
 };
 
 //------------------------------------------------------------------------------
-// A snapshotted representation of a (parent, child) task pair, for tracking
-// hierarchical profiles.
-
-struct BASE_EXPORT ParentChildPairSnapshot {
- public:
-  ParentChildPairSnapshot();
-  explicit ParentChildPairSnapshot(
-      const ThreadData::ParentChildPair& parent_child);
-  ~ParentChildPairSnapshot();
-
-  BirthOnThreadSnapshot parent;
-  BirthOnThreadSnapshot child;
-};
-
-//------------------------------------------------------------------------------
 // A snapshotted representation of the list of ThreadData objects for a process,
 // for a single profiling phase.
 
@@ -771,7 +791,6 @@
   ~ProcessDataPhaseSnapshot();
 
   std::vector<TaskSnapshot> tasks;
-  std::vector<ParentChildPairSnapshot> descendants;
 };
 
 //------------------------------------------------------------------------------
@@ -783,7 +802,7 @@
   ProcessDataSnapshot();
   ~ProcessDataSnapshot();
 
-  PhasedProcessDataSnapshotMap phased_process_data_snapshots;
+  PhasedProcessDataSnapshotMap phased_snapshots;
   base::ProcessId process_id;
 };
 
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
index 5455fef..3537e54 100644
--- a/base/tracked_objects_unittest.cc
+++ b/base/tracked_objects_unittest.cc
@@ -71,9 +71,9 @@
                                int count,
                                int run_ms,
                                int queue_ms) {
-    ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-    auto it = process_data.phased_process_data_snapshots.find(0);
-    ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+    ASSERT_EQ(1u, process_data.phased_snapshots.size());
+    auto it = process_data.phased_snapshots.find(0);
+    ASSERT_TRUE(it != process_data.phased_snapshots.end());
     const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
     ASSERT_EQ(1u, process_data_phase.tasks.size());
@@ -101,8 +101,6 @@
 
     EXPECT_EQ(death_thread, process_data_phase.tasks[0].death_thread_name);
 
-    EXPECT_EQ(0u, process_data_phase.descendants.size());
-
     EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
   }
 
@@ -122,7 +120,8 @@
 
 TEST_F(TrackedObjectsTest, TaskStopwatchNoStartStop) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -134,7 +133,8 @@
 TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
   // Minimal test doesn't even create any tasks.
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -145,19 +145,17 @@
   EXPECT_FALSE(data->next());
   EXPECT_EQ(data, ThreadData::Get());
   ThreadData::BirthMap birth_map;
-  ThreadData::DeathMap death_map;
-  ThreadData::ParentChildSet parent_child_set;
-  data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+  ThreadData::DeathsSnapshot deaths;
+  data->SnapshotMaps(0, &birth_map, &deaths);
   EXPECT_EQ(0u, birth_map.size());
-  EXPECT_EQ(0u, death_map.size());
-  EXPECT_EQ(0u, parent_child_set.size());
+  EXPECT_EQ(0u, deaths.size());
 
   // Clean up with no leaking.
   Reset();
 
   // Do it again, just to be sure we reset state completely.
-  EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
-      ThreadData::PROFILING_CHILDREN_ACTIVE));
+  EXPECT_TRUE(
+      ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE));
   EXPECT_FALSE(ThreadData::first());  // No activity even on this thread.
   data = ThreadData::Get();
   EXPECT_TRUE(ThreadData::first());  // Now class was constructed.
@@ -165,42 +163,38 @@
   EXPECT_FALSE(data->next());
   EXPECT_EQ(data, ThreadData::Get());
   birth_map.clear();
-  death_map.clear();
-  parent_child_set.clear();
-  data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+  deaths.clear();
+  data->SnapshotMaps(0, &birth_map, &deaths);
   EXPECT_EQ(0u, birth_map.size());
-  EXPECT_EQ(0u, death_map.size());
-  EXPECT_EQ(0u, parent_child_set.size());
+  EXPECT_EQ(0u, deaths.size());
 }
 
 TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
   // Instigate tracking on a single tracked object, on our thread.
   const char kFunction[] = "TinyStartupShutdown";
   Location location(kFunction, kFile, kLineNumber, NULL);
-  Births* first_birth = ThreadData::TallyABirthIfActive(location);
+  ThreadData::TallyABirthIfActive(location);
 
   ThreadData* data = ThreadData::first();
   ASSERT_TRUE(data);
   EXPECT_FALSE(data->next());
   EXPECT_EQ(data, ThreadData::Get());
   ThreadData::BirthMap birth_map;
-  ThreadData::DeathMap death_map;
-  ThreadData::ParentChildSet parent_child_set;
-  data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+  ThreadData::DeathsSnapshot deaths;
+  data->SnapshotMaps(0, &birth_map, &deaths);
   EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
   EXPECT_EQ(1, birth_map.begin()->second->birth_count());  // 1 birth.
-  EXPECT_EQ(0u, death_map.size());                         // No deaths.
-  EXPECT_EQ(0u, parent_child_set.size());                  // No children.
+  EXPECT_EQ(0u, deaths.size());                            // No deaths.
 
 
   // Now instigate another birth, while we are timing the run of the first
   // execution.
-  ThreadData::PrepareForStartOfRun(first_birth);
   // Create a child (using the same birth location).
   // TrackingInfo will call TallyABirth() during construction.
   const int32 start_time = 1;
@@ -218,30 +212,22 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
 
   birth_map.clear();
-  death_map.clear();
-  parent_child_set.clear();
-  data->SnapshotMaps(&birth_map, &death_map, &parent_child_set);
+  deaths.clear();
+  data->SnapshotMaps(0, &birth_map, &deaths);
   EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
   EXPECT_EQ(2, birth_map.begin()->second->birth_count());  // 2 births.
-  EXPECT_EQ(1u, death_map.size());                         // 1 location.
-  EXPECT_EQ(1, death_map.begin()->second.count());         // 1 death.
-  if (ThreadData::TrackingParentChildStatus()) {
-    EXPECT_EQ(1u, parent_child_set.size());                  // 1 child.
-    EXPECT_EQ(parent_child_set.begin()->first,
-              parent_child_set.begin()->second);
-  } else {
-    EXPECT_EQ(0u, parent_child_set.size());                  // no stats.
-  }
+  EXPECT_EQ(1u, deaths.size());                            // 1 location.
+  EXPECT_EQ(1, deaths.begin()->second.death_data.count);   // 1 death.
 
   // The births were at the same location as the one known death.
-  EXPECT_EQ(birth_map.begin()->second, death_map.begin()->first);
+  EXPECT_EQ(birth_map.begin()->second, deaths.begin()->first);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
 
-  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-  auto it = process_data.phased_process_data_snapshots.find(0);
-  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
   const ProcessDataPhaseSnapshot& process_data_phase = it->second;
   ASSERT_EQ(1u, process_data_phase.tasks.size());
   EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
@@ -261,43 +247,25 @@
   EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_max);
   EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sample);
   EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].death_thread_name);
-
-  if (ThreadData::TrackingParentChildStatus()) {
-    ASSERT_EQ(1u, process_data_phase.descendants.size());
-    EXPECT_EQ(kFile,
-              process_data_phase.descendants[0].parent.location.file_name);
-    EXPECT_EQ(kFunction,
-              process_data_phase.descendants[0].parent.location.function_name);
-    EXPECT_EQ(kLineNumber,
-              process_data_phase.descendants[0].parent.location.line_number);
-    EXPECT_EQ(kWorkerThreadName,
-              process_data_phase.descendants[0].parent.thread_name);
-    EXPECT_EQ(kFile,
-              process_data_phase.descendants[0].child.location.file_name);
-    EXPECT_EQ(kFunction,
-              process_data_phase.descendants[0].child.location.function_name);
-    EXPECT_EQ(kLineNumber,
-              process_data_phase.descendants[0].child.location.line_number);
-    EXPECT_EQ(kWorkerThreadName,
-              process_data_phase.descendants[0].child.thread_name);
-  } else {
-    EXPECT_EQ(0u, process_data_phase.descendants.size());
-  }
 }
 
-TEST_F(TrackedObjectsTest, DeathDataTest) {
+TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
   scoped_ptr<DeathData> data(new DeathData());
   ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
   EXPECT_EQ(data->run_duration_sum(), 0);
+  EXPECT_EQ(data->run_duration_max(), 0);
   EXPECT_EQ(data->run_duration_sample(), 0);
   EXPECT_EQ(data->queue_duration_sum(), 0);
+  EXPECT_EQ(data->queue_duration_max(), 0);
   EXPECT_EQ(data->queue_duration_sample(), 0);
   EXPECT_EQ(data->count(), 0);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
 
   int32 run_ms = 42;
   int32 queue_ms = 8;
@@ -305,31 +273,133 @@
   const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
   data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
   EXPECT_EQ(data->run_duration_sum(), run_ms);
+  EXPECT_EQ(data->run_duration_max(), run_ms);
   EXPECT_EQ(data->run_duration_sample(), run_ms);
   EXPECT_EQ(data->queue_duration_sum(), queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms);
   EXPECT_EQ(data->queue_duration_sample(), queue_ms);
   EXPECT_EQ(data->count(), 1);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
 
   data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
   EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+  EXPECT_EQ(data->run_duration_max(), run_ms);
   EXPECT_EQ(data->run_duration_sample(), run_ms);
   EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms);
   EXPECT_EQ(data->queue_duration_sample(), queue_ms);
   EXPECT_EQ(data->count(), 2);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+}
 
-  DeathDataSnapshot snapshot(*data);
-  EXPECT_EQ(2, snapshot.count);
-  EXPECT_EQ(2 * run_ms, snapshot.run_duration_sum);
-  EXPECT_EQ(run_ms, snapshot.run_duration_max);
-  EXPECT_EQ(run_ms, snapshot.run_duration_sample);
-  EXPECT_EQ(2 * queue_ms, snapshot.queue_duration_sum);
-  EXPECT_EQ(queue_ms, snapshot.queue_duration_max);
-  EXPECT_EQ(queue_ms, snapshot.queue_duration_sample);
+TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
+    return;
+  }
+
+  scoped_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+
+  int32 run_ms = 42;
+  int32 queue_ms = 8;
+
+  const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+
+  data->OnProfilingPhaseCompleted(123);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+  EXPECT_EQ(data->run_duration_max(), 0);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), 0);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 2);
+  ASSERT_NE(nullptr, data->last_phase_snapshot());
+  EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+  EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+  EXPECT_EQ(2 * run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sum);
+  EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+  EXPECT_EQ(run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sum);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_max);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sample);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+
+  int32 run_ms1 = 21;
+  int32 queue_ms1 = 4;
+
+  data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
+  EXPECT_EQ(data->run_duration_max(), run_ms1);
+  EXPECT_EQ(data->run_duration_sample(), run_ms1);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms + queue_ms1);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms1);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms1);
+  EXPECT_EQ(data->count(), 3);
+  ASSERT_NE(nullptr, data->last_phase_snapshot());
+  EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+  EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+  EXPECT_EQ(2 * run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sum);
+  EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+  EXPECT_EQ(run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sum);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_max);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sample);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+}
+
+TEST_F(TrackedObjectsTest, Delta) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
+    return;
+  }
+
+  DeathDataSnapshot snapshot;
+  snapshot.count = 10;
+  snapshot.run_duration_sum = 100;
+  snapshot.run_duration_max = 50;
+  snapshot.run_duration_sample = 25;
+  snapshot.queue_duration_sum = 200;
+  snapshot.queue_duration_max = 101;
+  snapshot.queue_duration_sample = 26;
+
+  DeathDataSnapshot older_snapshot;
+  older_snapshot.count = 2;
+  older_snapshot.run_duration_sum = 95;
+  older_snapshot.run_duration_max = 48;
+  older_snapshot.run_duration_sample = 22;
+  older_snapshot.queue_duration_sum = 190;
+  older_snapshot.queue_duration_max = 99;
+  older_snapshot.queue_duration_sample = 21;
+
+  const DeathDataSnapshot& delta = snapshot.Delta(older_snapshot);
+  EXPECT_EQ(8, delta.count);
+  EXPECT_EQ(5, delta.run_duration_sum);
+  EXPECT_EQ(50, delta.run_duration_max);
+  EXPECT_EQ(25, delta.run_duration_sample);
+  EXPECT_EQ(10, delta.queue_duration_sum);
+  EXPECT_EQ(101, delta.queue_duration_max);
+  EXPECT_EQ(26, delta.queue_duration_sample);
 }
 
 TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotWorkerThread) {
   // Start in the deactivated state.
   if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -338,21 +408,23 @@
   TallyABirth(location, std::string());
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
 
-  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-  auto it = process_data.phased_process_data_snapshots.find(0);
-  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
   const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
-  EXPECT_EQ(0u, process_data_phase.tasks.size());
-  EXPECT_EQ(0u, process_data_phase.descendants.size());
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
 TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotMainThread) {
   // Start in the deactivated state.
   if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -361,21 +433,23 @@
   TallyABirth(location, kMainThreadName);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
 
-  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-  auto it = process_data.phased_process_data_snapshots.find(0);
-  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
   const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
-  EXPECT_EQ(0u, process_data_phase.tasks.size());
-  EXPECT_EQ(0u, process_data_phase.descendants.size());
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
 TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotWorkerThread) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -384,14 +458,15 @@
   TallyABirth(location, std::string());
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
                           kStillAlive, 1, 0, 0);
 }
 
 TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotMainThread) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -400,14 +475,15 @@
   TallyABirth(location, kMainThreadName);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kMainThreadName, kStillAlive,
                           1, 0, 0);
 }
 
 TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -432,18 +508,395 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
                           kMainThreadName, 1, 2, 4);
 }
 
+TEST_F(TrackedObjectsTest, TwoPhases) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
+    return;
+  }
+
+  const char kFunction[] = "TwoPhases";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted1 = TrackedTime::FromMilliseconds(9);
+  const base::TimeTicks kDelayedStartTime1 = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task1(location, kDelayedStartTime1);
+  pending_task1.time_posted = kTimePosted1;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun1 = 11;
+  const unsigned int kEndOfRun1 = 21;
+  SetTestTime(kStartOfRun1);
+  TaskStopwatch stopwatch1;
+  stopwatch1.Start();
+  SetTestTime(kEndOfRun1);
+  stopwatch1.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task1, stopwatch1);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, ThreePhases) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
+    return;
+  }
+
+  const char kFunction[] = "ThreePhases";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  // Phase 0
+  {
+    TallyABirth(location, kMainThreadName);
+
+    // TrackingInfo will call TallyABirth() during construction.
+    SetTestTime(10);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(17);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(23);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  // Phase 1
+  {
+    TallyABirth(location, kMainThreadName);
+
+    SetTestTime(30);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(35);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(39);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(1);
+
+  // Phase 2
+  {
+    TallyABirth(location, kMainThreadName);
+
+    // TrackingInfo will call TallyABirth() during construction.
+    SetTestTime(40);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(43);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(45);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  // Snapshot and check results.
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(2, &process_data);
+
+  ASSERT_EQ(3u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  auto it2 = process_data.phased_snapshots.find(2);
+  ASSERT_TRUE(it2 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase2 = it2->second;
+
+  ASSERT_EQ(1u, process_data_phase2.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase2.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase2.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase2.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase2.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesSecondEmpty) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
+    return;
+  }
+
+  const char kFunction[] = "TwoPhasesSecondEmpty";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::InitializeThreadContext(kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(0u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesFirstEmpty) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
+    return;
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  const char kFunction[] = "TwoPhasesSecondEmpty";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::InitializeThreadContext(kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
 // We will deactivate tracking after the birth, and before the death, and
 // demonstrate that the lifecycle is completely tallied. This ensures that
 // our tallied births are matched by tallied deaths (except for when the
 // task is still running, or is queued).
 TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -472,7 +925,7 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
                           kMainThreadName, 1, 2, 4);
 }
@@ -482,6 +935,7 @@
 TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
   // Start in the deactivated state.
   if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -506,21 +960,23 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
 
-  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-  auto it = process_data.phased_process_data_snapshots.find(0);
-  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
   const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
-  EXPECT_EQ(0u, process_data_phase.tasks.size());
-  EXPECT_EQ(0u, process_data_phase.descendants.size());
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
 TEST_F(TrackedObjectsTest, TwoLives) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -556,14 +1012,15 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task2, stopwatch2);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
                           kMainThreadName, 2, 2, 4);
 }
 
 TEST_F(TrackedObjectsTest, DifferentLives) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -596,11 +1053,11 @@
   pending_task2.time_posted = kTimePosted;  // Overwrite implied Now().
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
 
-  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-  auto it = process_data.phased_process_data_snapshots.find(0);
-  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
   const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
   ASSERT_EQ(2u, process_data_phase.tasks.size());
@@ -633,13 +1090,13 @@
   EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_max);
   EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sample);
   EXPECT_EQ(kStillAlive, process_data_phase.tasks[1].death_thread_name);
-  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
 TEST_F(TrackedObjectsTest, TaskWithNestedExclusion) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -669,14 +1126,15 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
                           kMainThreadName, 1, 6, 4);
 }
 
 TEST_F(TrackedObjectsTest, TaskWith2NestedExclusions) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -712,14 +1170,15 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
   ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
                           kMainThreadName, 1, 13, 4);
 }
 
 TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
   if (!ThreadData::InitializeAndSetTrackingStatus(
-          ThreadData::PROFILING_CHILDREN_ACTIVE)) {
+          ThreadData::PROFILING_ACTIVE)) {
+    // Don't run the test if task tracking is not compiled in.
     return;
   }
 
@@ -765,11 +1224,11 @@
   ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
 
   ProcessDataSnapshot process_data;
-  ThreadData::Snapshot(&process_data);
+  ThreadData::Snapshot(0, &process_data);
 
-  ASSERT_EQ(1u, process_data.phased_process_data_snapshots.size());
-  auto it = process_data.phased_process_data_snapshots.find(0);
-  ASSERT_TRUE(it != process_data.phased_process_data_snapshots.end());
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
   const ProcessDataPhaseSnapshot& process_data_phase = it->second;
 
   // The order in which the two task follow is platform-dependent.
@@ -808,7 +1267,6 @@
   EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_max);
   EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sample);
   EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].death_thread_name);
-  EXPECT_EQ(0u, process_data_phase.descendants.size());
   EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
 }
 
diff --git a/base/vlog.cc b/base/vlog.cc
index 8612071..519ceff 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -50,7 +50,6 @@
     : min_log_level_(min_log_level) {
   DCHECK(min_log_level != NULL);
 
-  typedef std::pair<std::string, std::string> KVPair;
   int vlog_level = 0;
   if (!v_switch.empty()) {
     if (base::StringToInt(v_switch, &vlog_level)) {
@@ -60,13 +59,13 @@
     }
   }
 
-  std::vector<KVPair> kv_pairs;
+  base::StringPairs kv_pairs;
   if (!base::SplitStringIntoKeyValuePairs(
           vmodule_switch, '=', ',', &kv_pairs)) {
     DLOG(WARNING) << "Could not fully parse vmodule switch \""
                   << vmodule_switch << "\"";
   }
-  for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
+  for (base::StringPairs::const_iterator it = kv_pairs.begin();
        it != kv_pairs.end(); ++it) {
     VmodulePattern pattern(it->first);
     if (!base::StringToInt(it->second, &pattern.vlog_level)) {
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
index 35609fc..5ebe185 100644
--- a/base/win/object_watcher.cc
+++ b/base/win/object_watcher.cc
@@ -92,7 +92,7 @@
   // The destructor blocks on any callbacks that are in flight, so we know that
   // that is always a pointer to a valid ObjectWater.
   ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
-  that->origin_loop_->PostTask(FROM_HERE, that->callback_);
+  that->origin_loop_->task_runner()->PostTask(FROM_HERE, that->callback_);
   that->callback_.Reset();
 }
 
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
index 19b381d..692b7b6 100644
--- a/base/win/pe_image.cc
+++ b/base/win/pe_image.cc
@@ -568,12 +568,11 @@
   if (NULL == section_header)
     return false;
 
-#pragma warning(suppress : 4302) // pointer truncation
-  // These casts generate warnings because they are 32 bit specific.
   // Don't follow the virtual RVAToAddr, use the one on the base.
-  DWORD offset_within_section = reinterpret_cast<DWORD>(address) -
-                                    reinterpret_cast<DWORD>(PEImage::RVAToAddr(
-                                        section_header->VirtualAddress));
+  DWORD offset_within_section =
+      static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
+      static_cast<DWORD>(reinterpret_cast<uintptr_t>(
+          PEImage::RVAToAddr(section_header->VirtualAddress)));
 
   *on_disk_offset = section_header->PointerToRawData + offset_within_section;
   return true;
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
index 9aead96..2452067 100644
--- a/base/win/scoped_hdc.h
+++ b/base/win/scoped_hdc.h
@@ -68,7 +68,7 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits);
 };
 
-typedef GenericScopedHandle<CreateDCTraits, VerifierTraits> ScopedCreateDC;
+typedef GenericScopedHandle<CreateDCTraits, DummyVerifierTraits> ScopedCreateDC;
 
 }  // namespace win
 }  // namespace base
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
index 284a6ef..d530d5b 100644
--- a/base/win/scoped_variant_unittest.cc
+++ b/base/win/scoped_variant_unittest.cc
@@ -27,34 +27,34 @@
   FakeComObject() : ref_(0) {
   }
 
-  STDMETHOD_(DWORD, AddRef)() {
+  STDMETHOD_(DWORD, AddRef)() override {
     ref_++;
     return ref_;
   }
 
-  STDMETHOD_(DWORD, Release)() {
+  STDMETHOD_(DWORD, Release)() override {
     ref_--;
     return ref_;
   }
 
-  STDMETHOD(QueryInterface)(REFIID, void**) {
+  STDMETHOD(QueryInterface)(REFIID, void**) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetTypeInfoCount)(UINT*) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) override {
     return E_NOTIMPL;
   }
 
-  STDMETHOD(GetTypeInfoCount)(UINT*) {
-    return E_NOTIMPL;
-  }
-
-  STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) {
-    return E_NOTIMPL;
-  }
-
-  STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) {
-    return E_NOTIMPL;
-  }
-
-  STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*,
-                    EXCEPINFO*, UINT*) {
+  STDMETHOD(Invoke)(DISPID,
+                    REFIID,
+                    LCID,
+                    WORD,
+                    DISPPARAMS*,
+                    VARIANT*,
+                    EXCEPINFO*,
+                    UINT*) override {
     return E_NOTIMPL;
   }
 
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
index 207fdbe..f8b2182 100644
--- a/base/win/shortcut.cc
+++ b/base/win/shortcut.cc
@@ -321,8 +321,8 @@
   if (GetVersion() < VERSION_WIN7)
     return false;
 
-  int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut,
-      NULL, NULL, 0));
+  intptr_t result = reinterpret_cast<intptr_t>(
+      ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
   return result > 32;
 }
 
@@ -333,8 +333,8 @@
   if (GetVersion() < VERSION_WIN7)
     return false;
 
-  int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
-      shortcut, NULL, NULL, 0));
+  intptr_t result = reinterpret_cast<intptr_t>(
+      ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
   return result > 32;
 }
 
diff --git a/base/win/startup_information.h b/base/win/startup_information.h
index e7e21cb..73d9f3e 100644
--- a/base/win/startup_information.h
+++ b/base/win/startup_information.h
@@ -24,6 +24,8 @@
   bool InitializeProcThreadAttributeList(DWORD attribute_count);
 
   // Sets one entry in the initialized attribute list.
+  // |value| needs to live at least as long as the StartupInformation object
+  // this is called on.
   bool UpdateProcThreadAttribute(DWORD_PTR attribute,
                                  void* value,
                                  size_t size);
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 59ae375..c5b06c4 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -428,7 +428,7 @@
                                   NULL,
                                   NULL,
                                   SW_SHOW);
-  return reinterpret_cast<int>(ret) > 32;
+  return reinterpret_cast<intptr_t>(ret) > 32;
 }
 
 bool DismissVirtualKeyboard() {
diff --git a/build/all.gyp b/build/all.gyp
index 255a35c..1866c2e 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -124,6 +124,7 @@
             '../jingle/jingle.gyp:*',
             '../media/cast/cast.gyp:*',
             '../media/media.gyp:*',
+            '../media/midi/midi.gyp:*',
             '../mojo/mojo.gyp:*',
             '../mojo/mojo_base.gyp:*',
             '../ppapi/ppapi.gyp:*',
@@ -318,6 +319,7 @@
         '../ui/base/ui_base_tests.gyp:ui_base_unittests',
         '../ui/display/display.gyp:display_unittests',
         '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+        '../ui/gl/gl_tests.gyp:gl_unittests',
         '../url/url.gyp:url_unittests',
       ],
       'conditions': [
@@ -344,6 +346,7 @@
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/cast/cast.gyp:cast_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../mojo/mojo.gyp:mojo',
             '../ppapi/ppapi_internal.gyp:ppapi_unittests',
             '../remoting/remoting.gyp:remoting_unittests',
@@ -567,6 +570,7 @@
             '../content/content_shell_and_tests.gyp:content_shell',
             '../gpu/gpu.gyp:gpu_perftests',
             '../media/media.gyp:media_perftests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
             '../tools/telemetry/telemetry.gyp:*',
           ],
@@ -681,6 +685,7 @@
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../third_party/webrtc/tools/tools.gyp:frame_analyzer',
             '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter',
           ],
@@ -814,6 +819,8 @@
             '../ipc/ipc.gyp:ipc_tests',
             '../media/media.gyp:media_perftests_apk',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests_apk',
+            '../media/midi/midi.gyp:midi_unittests',
             '../net/net.gyp:net_unittests',
             '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
             '../skia/skia_tests.gyp:skia_unittests',
@@ -843,6 +850,7 @@
             '../gpu/gpu.gyp:gpu_unittests_apk',
             '../ipc/ipc.gyp:ipc_tests_apk',
             '../media/media.gyp:media_unittests_apk',
+            '../media/midi/midi.gyp:midi_unittests_apk',
             '../net/net.gyp:net_unittests_apk',
             '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests_apk',
             '../skia/skia_tests.gyp:skia_unittests_apk',
@@ -853,6 +861,7 @@
             '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
             '../ui/events/events.gyp:events_unittests_apk',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
+            '../ui/gl/gl_tests.gyp:gl_unittests_apk',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_apk',
           ],
           'conditions': [
@@ -929,6 +938,7 @@
             '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../ppapi/ppapi_internal.gyp:ppapi_unittests',
             '../printing/printing.gyp:printing_unittests',
             '../remoting/remoting.gyp:remoting_unittests',
@@ -944,6 +954,7 @@
             '../tools/telemetry/telemetry.gyp:*',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
             '../url/url.gyp:url_unittests',
           ],
         },
@@ -968,6 +979,7 @@
             '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../ppapi/ppapi_internal.gyp:ppapi_unittests',
             '../printing/printing.gyp:printing_unittests',
             '../remoting/remoting.gyp:remoting_unittests',
@@ -982,6 +994,7 @@
             '../tools/telemetry/telemetry.gyp:*',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
             '../url/url.gyp:url_unittests',
           ],
         },
@@ -995,6 +1008,7 @@
             '../ipc/ipc.gyp:ipc_tests',
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../net/net.gyp:net_unittests',
             '../printing/printing.gyp:printing_unittests',
             '../remoting/remoting.gyp:remoting_unittests',
@@ -1018,6 +1032,7 @@
             '../ipc/ipc.gyp:ipc_tests',
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../net/net.gyp:net_unittests',
             '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
             '../printing/printing.gyp:printing_unittests',
@@ -1031,6 +1046,7 @@
             '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
             '../url/url.gyp:url_unittests',
           ],
         },
@@ -1069,6 +1085,7 @@
             '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../ppapi/ppapi_internal.gyp:ppapi_unittests',
             '../printing/printing.gyp:printing_unittests',
             '../remoting/remoting.gyp:remoting_unittests',
@@ -1084,6 +1101,7 @@
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/events/events.gyp:events_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
             '../ui/views/views.gyp:views_unittests',
             '../url/url.gyp:url_unittests',
@@ -1108,6 +1126,7 @@
             '../ipc/ipc.gyp:ipc_tests',
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../net/net.gyp:net_unittests',
             '../printing/printing.gyp:printing_unittests',
             '../remoting/remoting.gyp:remoting_unittests',
@@ -1166,6 +1185,7 @@
             '../jingle/jingle.gyp:jingle_unittests',
             '../media/cast/cast.gyp:cast_unittests',
             '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
             '../mojo/mojo.gyp:mojo',
             '../net/net.gyp:net_unittests',
             '../printing/printing.gyp:printing_unittests',
@@ -1186,6 +1206,7 @@
             '../ui/display/display.gyp:display_unittests',
             '../ui/events/events.gyp:events_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
             '../ui/keyboard/keyboard.gyp:keyboard_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
             '../url/url.gyp:url_unittests',
@@ -1234,12 +1255,14 @@
                 '../chrome/chrome.gyp:sync_integration_tests',
                 '../ipc/ipc.gyp:ipc_tests',
                 '../media/media.gyp:media_unittests',
+                '../media/midi/midi.gyp:midi_unittests',
                 '../net/net.gyp:net_unittests_run',
                 '../printing/printing.gyp:printing_unittests',
                 '../sql/sql.gyp:sql_unittests',
                 '../sync/sync.gyp:sync_unit_tests',
                 '../ui/base/ui_base_tests.gyp:ui_base_unittests',
                 '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+                '../ui/gl/gl_tests.gyp:gl_unittests',
                 '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
                 '../ui/views/views.gyp:views_unittests',
                 '../url/url.gyp:url_unittests',
@@ -1273,6 +1296,7 @@
             '../ui/display/display.gyp:display_unittests',
             '../ui/events/events.gyp:*',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
             '../ui/keyboard/keyboard.gyp:*',
             '../ui/snapshot/snapshot.gyp:snapshot_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 92095be..6e0a3de 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -42,6 +42,7 @@
       input_api,
       output_api,
       unit_tests=[
+          J('pylib', 'base', 'test_dispatcher_unittest.py'),
           J('pylib', 'device', 'battery_utils_test.py'),
           J('pylib', 'device', 'device_utils_test.py'),
           J('pylib', 'device', 'logcat_monitor_test.py'),
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index 4e62332..778a8c2 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -15,7 +15,9 @@
 def DoDex(options, paths):
   dx_binary = os.path.join(options.android_sdk_tools, 'dx')
   # See http://crbug.com/272064 for context on --force-jumbo.
-  dex_cmd = [dx_binary, '--dex', '--force-jumbo', '--output', options.dex_path]
+  # --num-threads=10 made final dexing go from 10s -> 5s on a z620.
+  dex_cmd = [dx_binary, '--num-threads=10', '--dex', '--force-jumbo',
+             '--output', options.dex_path]
   if options.no_locals != '0':
     dex_cmd.append('--no-locals')
 
diff --git a/build/android/gyp/jinja_template.py b/build/android/gyp/jinja_template.py
index 6653f21..e7c9a34 100755
--- a/build/android/gyp/jinja_template.py
+++ b/build/android/gyp/jinja_template.py
@@ -51,7 +51,7 @@
                                 os.path.abspath(inputs_base_dir))
       if relpath.startswith(os.pardir):
         raise Exception('input file %s is not contained in inputs base dir %s'
-                        % input_filename, inputs_base_dir)
+                        % (input_filename, inputs_base_dir))
 
       output_filename = os.path.join(temp_dir, relpath)
       parent_dir = os.path.dirname(output_filename)
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
index 1ca0338..2a7fdd3 100644
--- a/build/android/pylib/base/base_test_runner.py
+++ b/build/android/pylib/base/base_test_runner.py
@@ -26,14 +26,15 @@
 class BaseTestRunner(object):
   """Base class for running tests on a single device."""
 
-  def __init__(self, device_serial, tool):
+  def __init__(self, device, tool):
     """
       Args:
-        device: Tests will run on the device of this ID.
+        device: An instance of DeviceUtils that the tests will run on.
         tool: Name of the Valgrind tool.
     """
-    self.device_serial = device_serial
-    self.device = device_utils.DeviceUtils(device_serial)
+    assert isinstance(device, device_utils.DeviceUtils)
+    self.device = device
+    self.device_serial = self.device.adb.GetDeviceSerial()
     self.tool = CreateTool(tool, self.device)
     self._http_server = None
     self._forwarder_device_port = 8000
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index 1a8e0c1..f919965 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -21,7 +21,6 @@
 import logging
 import threading
 
-from pylib import android_commands
 from pylib import constants
 from pylib.base import base_test_result
 from pylib.base import test_collection
@@ -102,7 +101,7 @@
   for test in collection:
     watcher.Reset()
     try:
-      if runner.device_serial not in android_commands.GetAttachedDevices():
+      if not runner.device.IsOnline():
         # Device is unresponsive, stop handling tests on this device.
         msg = 'Device %s is unresponsive.' % runner.device_serial
         logging.warning(msg)
@@ -150,10 +149,7 @@
     runner = runner_factory(device, index)
     runner.SetUp()
     out_runners.append(runner)
-  except (device_errors.DeviceUnreachableError,
-          # TODO(jbudorick) Remove this once the underlying implementations
-          #                 for the above are switched or wrapped.
-          android_commands.errors.DeviceUnresponsiveError) as e:
+  except device_errors.DeviceUnreachableError as e:
     logging.warning('Failed to create shard for %s: [%s]', device, e)
 
 
@@ -195,10 +191,7 @@
   # Catch DeviceUnreachableErrors and set a warning exit code
   try:
     workers.JoinAll(watcher)
-  except (device_errors.DeviceUnreachableError,
-          # TODO(jbudorick) Remove this once the underlying implementations
-          #                 for the above are switched or wrapped.
-          android_commands.errors.DeviceUnresponsiveError) as e:
+  except device_errors.DeviceUnreachableError as e:
     logging.error(e)
 
   if not all((len(tc) == 0 for tc in test_collections)):
@@ -236,7 +229,7 @@
   threads = reraiser_thread.ReraiserThreadGroup(
       [reraiser_thread.ReraiserThread(_SetUp,
                                       [runner_factory, d, runners, counter],
-                                      name=d[-4:])
+                                      name=str(d)[-4:])
        for d in devices])
   threads.StartAll()
   threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
@@ -333,10 +326,7 @@
   finally:
     try:
       _TearDownRunners(runners, setup_timeout)
-    except (device_errors.DeviceUnreachableError,
-            # TODO(jbudorick) Remove this once the underlying implementations
-            #                 for the above are switched or wrapped.
-            android_commands.errors.DeviceUnresponsiveError) as e:
+    except device_errors.DeviceUnreachableError as e:
       logging.warning('Device unresponsive during TearDown: [%s]', e)
     except Exception as e:
       logging.error('Unexpected exception caught during TearDown: %s' % str(e))
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
old mode 100644
new mode 100755
index b57cca9..cace9a6
--- a/build/android/pylib/base/test_dispatcher_unittest.py
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 # 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.
@@ -10,27 +11,38 @@
 import sys
 import unittest
 
-sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),
-                os.pardir, os.pardir))
 
-# Mock out android_commands.GetAttachedDevices().
-from pylib import android_commands
-android_commands.GetAttachedDevices = lambda: ['0', '1']
 from pylib import constants
 from pylib.base import base_test_result
 from pylib.base import test_collection
 from pylib.base import test_dispatcher
+from pylib.device import adb_wrapper
+from pylib.device import device_utils
 from pylib.utils import watchdog_timer
 
+sys.path.append(
+    os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
 
 class TestException(Exception):
   pass
 
 
+def _MockDevice(serial):
+  d = mock.MagicMock(spec=device_utils.DeviceUtils)
+  d.__str__.return_value = serial
+  d.adb = mock.MagicMock(spec=adb_wrapper.AdbWrapper)
+  d.adb.GetDeviceSerial = mock.MagicMock(return_value=serial)
+  d.IsOnline = mock.MagicMock(return_value=True)
+  return d
+
+
 class MockRunner(object):
   """A mock TestRunner."""
-  def __init__(self, device='0', shard_index=0):
-    self.device_serial = device
+  def __init__(self, device=None, shard_index=0):
+    self.device = device or _MockDevice('0')
+    self.device_serial = self.device.adb.GetDeviceSerial()
     self.shard_index = shard_index
     self.setups = 0
     self.teardowns = 0
@@ -57,7 +69,7 @@
 
 
 class MockRunnerFailTwice(MockRunner):
-  def __init__(self, device='0', shard_index=0):
+  def __init__(self, device=None, shard_index=0):
     super(MockRunnerFailTwice, self).__init__(device, shard_index)
     self._fails = 0
 
@@ -111,7 +123,7 @@
   def testSetUp(self):
     runners = []
     counter = test_dispatcher._ThreadSafeCounter()
-    test_dispatcher._SetUp(MockRunner, '0', runners, counter)
+    test_dispatcher._SetUp(MockRunner, _MockDevice('0'), runners, counter)
     self.assertEqual(len(runners), 1)
     self.assertEqual(runners[0].setups, 1)
 
@@ -135,7 +147,8 @@
     self.test_collection_factory = lambda: shared_test_collection
 
   def testCreate(self):
-    runners = test_dispatcher._CreateRunners(MockRunner, ['0', '1'])
+    runners = test_dispatcher._CreateRunners(
+        MockRunner, [_MockDevice('0'), _MockDevice('1')])
     for runner in runners:
       self.assertEqual(runner.setups, 1)
     self.assertEqual(set([r.device_serial for r in runners]),
@@ -144,27 +157,29 @@
                      set([0, 1]))
 
   def testRun(self):
-    runners = [MockRunner('0'), MockRunner('1')]
+    runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
     results, exit_code = test_dispatcher._RunAllTests(
         runners, self.test_collection_factory, 0)
     self.assertEqual(len(results.GetPass()), len(self.tests))
     self.assertEqual(exit_code, 0)
 
   def testTearDown(self):
-    runners = [MockRunner('0'), MockRunner('1')]
+    runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
     test_dispatcher._TearDownRunners(runners)
     for runner in runners:
       self.assertEqual(runner.teardowns, 1)
 
   def testRetry(self):
-    runners = test_dispatcher._CreateRunners(MockRunnerFail, ['0', '1'])
+    runners = test_dispatcher._CreateRunners(
+        MockRunnerFail, [_MockDevice('0'), _MockDevice('1')])
     results, exit_code = test_dispatcher._RunAllTests(
         runners, self.test_collection_factory, 0)
     self.assertEqual(len(results.GetFail()), len(self.tests))
     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
 
   def testReraise(self):
-    runners = test_dispatcher._CreateRunners(MockRunnerException, ['0', '1'])
+    runners = test_dispatcher._CreateRunners(
+        MockRunnerException, [_MockDevice('0'), _MockDevice('1')])
     with self.assertRaises(TestException):
       test_dispatcher._RunAllTests(runners, self.test_collection_factory, 0)
 
@@ -174,7 +189,8 @@
   @staticmethod
   def _RunShard(runner_factory):
     return test_dispatcher.RunTests(
-        ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=True)
+        ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
+        shard=True)
 
   def testShard(self):
     results, exit_code = TestShard._RunShard(MockRunner)
@@ -189,7 +205,7 @@
 
   def testNoTests(self):
     results, exit_code = test_dispatcher.RunTests(
-        [], MockRunner, ['0', '1'], shard=True)
+        [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=True)
     self.assertEqual(len(results.GetAll()), 0)
     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
 
@@ -199,7 +215,8 @@
   @staticmethod
   def _RunReplicate(runner_factory):
     return test_dispatcher.RunTests(
-        ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=False)
+        ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
+        shard=False)
 
   def testReplicate(self):
     results, exit_code = TestReplicate._RunReplicate(MockRunner)
@@ -215,7 +232,7 @@
 
   def testNoTests(self):
     results, exit_code = test_dispatcher.RunTests(
-        [], MockRunner, ['0', '1'], shard=False)
+        [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=False)
     self.assertEqual(len(results.GetAll()), 0)
     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
 
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index 6e92f6d..025860c 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -102,7 +102,7 @@
         'org.chromium.android_webview.test'),
     'gtest': PackageInfo(
         'org.chromium.native_test',
-        'org.chromium.native_test.ChromeNativeTestActivity',
+        'org.chromium.native_test.NativeTestActivity',
         '/data/local/tmp/chrome-native-tests-command-line',
         None,
         None),
@@ -229,7 +229,8 @@
   try:
     return os.environ['BUILDTYPE']
   except KeyError:
-    raise Exception('The BUILDTYPE environment variable has not been set')
+    raise EnvironmentError(
+        'The BUILDTYPE environment variable has not been set')
 
 
 def SetBuildType(build_type):
@@ -240,7 +241,7 @@
   os.environ['CHROMIUM_OUT_DIR'] = build_directory
 
 
-def SetOutputDirectort(output_directory):
+def SetOutputDirectory(output_directory):
   os.environ['CHROMIUM_OUTPUT_DIR'] = output_directory
 
 
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index 20787c1..8e8abf8 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -450,7 +450,7 @@
       timeout: (optional) Timeout per try in seconds.
       retries: (optional) Number of retries to attempt.
     """
-    cmd = ['backup', path]
+    cmd = ['backup', '-f', path]
     if apk:
       cmd.append('-apk')
     if shared:
@@ -542,6 +542,24 @@
       raise device_errors.AdbCommandFailedError(
           ['root'], output, device_serial=self._device_serial)
 
+  def Emu(self, cmd, timeout=_DEFAULT_TIMEOUT,
+               retries=_DEFAULT_RETRIES):
+    """Runs an emulator console command.
+
+    See http://developer.android.com/tools/devices/emulator.html#console
+
+    Args:
+      cmd: The command to run on the emulator console.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      The output of the emulator console command.
+    """
+    if isinstance(cmd, basestring):
+      cmd = [cmd]
+    return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)
+
   @property
   def is_emulator(self):
     return _EMULATOR_RE.match(self._device_serial)
diff --git a/build/android/pylib/device/battery_utils_test.py b/build/android/pylib/device/battery_utils_test.py
index 15b4c34..434b9d8 100755
--- a/build/android/pylib/device/battery_utils_test.py
+++ b/build/android/pylib/device/battery_utils_test.py
@@ -14,7 +14,6 @@
 import sys
 import unittest
 
-from pylib import android_commands
 from pylib import constants
 from pylib.device import battery_utils
 from pylib.device import device_errors
@@ -62,8 +61,7 @@
 
   def testInitWithDeviceUtil(self):
     serial = '0fedcba987654321'
-    a = android_commands.AndroidCommands(device=serial)
-    d = device_utils.DeviceUtils(a)
+    d = device_utils.DeviceUtils(serial)
     b = battery_utils.BatteryUtils(d)
     self.assertEqual(d, b._device)
 
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 46aec6f..091bb8e 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -175,6 +175,29 @@
     assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
     assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
 
+  def __eq__(self, other):
+    """Checks whether |other| refers to the same device as |self|.
+
+    Args:
+      other: The object to compare to. This can be a basestring, an instance
+        of adb_wrapper.AdbWrapper, or an instance of DeviceUtils.
+    Returns:
+      Whether |other| refers to the same device as |self|.
+    """
+    return self.adb.GetDeviceSerial() == str(other)
+
+  def __lt__(self, other):
+    """Compares two instances of DeviceUtils.
+
+    This merely compares their serial numbers.
+
+    Args:
+      other: The instance of DeviceUtils to compare to.
+    Returns:
+      Whether |self| is less than |other|.
+    """
+    return self.adb.GetDeviceSerial() < other.adb.GetDeviceSerial()
+
   def __str__(self):
     """Returns the device serial."""
     return self.adb.GetDeviceSerial()
@@ -535,9 +558,9 @@
         with device_temp_file.DeviceTempFile(self.adb) as large_output_file:
           cmd = '%s > %s' % (cmd, large_output_file.name)
           logging.info('Large output mode enabled. Will write output to device '
-                       ' and read results from file.')
+                       'and read results from file.')
           handle_large_command(cmd)
-          return self.ReadFile(large_output_file.name)
+          return self.ReadFile(large_output_file.name, force_pull=True)
       else:
         try:
           return handle_large_command(cmd)
@@ -853,13 +876,17 @@
     if not real_device_path:
       return [(host_path, device_path)]
 
-    host_checksums = md5sum.CalculateHostMd5Sums([real_host_path])
-    device_paths_to_md5 = (
-        real_device_path if os.path.isfile(real_host_path)
-        else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
-              for p in host_checksums.iterkeys()))
-    device_checksums = md5sum.CalculateDeviceMd5Sums(
-        device_paths_to_md5, self)
+    try:
+      host_checksums = md5sum.CalculateHostMd5Sums([real_host_path])
+      device_paths_to_md5 = (
+          real_device_path if os.path.isfile(real_host_path)
+          else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
+                for p in host_checksums.iterkeys()))
+      device_checksums = md5sum.CalculateDeviceMd5Sums(
+          device_paths_to_md5, self)
+    except EnvironmentError as e:
+      logging.warning('Error calculating md5: %s', e)
+      return [(host_path, device_path)]
 
     if os.path.isfile(host_path):
       host_checksum = host_checksums.get(real_host_path)
@@ -1016,7 +1043,7 @@
       + r'(?P<date>\S+) +(?P<time>\S+) +(?P<name>.+)$')
 
   @decorators.WithTimeoutAndRetriesFromInstance()
-  def ReadFile(self, device_path, as_root=False,
+  def ReadFile(self, device_path, as_root=False, force_pull=False,
                timeout=None, retries=None):
     """Reads the contents of a file from the device.
 
@@ -1025,6 +1052,9 @@
                    from the device.
       as_root: A boolean indicating whether the read should be executed with
                root privileges.
+      force_pull: A boolean indicating whether to force the operation to be
+          performed by pulling a file from the device. The default is, when the
+          contents are short, to retrieve the contents using cat instead.
       timeout: timeout in seconds
       retries: number of retries
 
@@ -1038,20 +1068,20 @@
       CommandTimeoutError on timeout.
       DeviceUnreachableError on missing device.
     """
-    # TODO(jbudorick): Implement a generic version of Stat() that handles
-    # as_root=True, then switch this implementation to use that.
-    size = None
-    ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root,
-                                  check_return=True)
-    for line in ls_out:
-      m = self._LS_RE.match(line)
-      if m and m.group('name') == posixpath.basename(device_path):
-        size = int(m.group('size'))
-        break
-    else:
+    def get_size(path):
+      # TODO(jbudorick): Implement a generic version of Stat() that handles
+      # as_root=True, then switch this implementation to use that.
+      ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root,
+                                    check_return=True)
+      for line in ls_out:
+        m = self._LS_RE.match(line)
+        if m and m.group('name') == posixpath.basename(device_path):
+          return int(m.group('size'))
       logging.warning('Could not determine size of %s.', device_path)
+      return None
 
-    if 0 < size <= self._MAX_ADB_OUTPUT_LENGTH:
+    if (not force_pull
+        and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH):
       return _JoinLines(self.RunShellCommand(
           ['cat', device_path], as_root=as_root, check_return=True))
     elif as_root and self.NeedsSU():
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 4301e9d..e5e3936 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -161,6 +161,73 @@
         msg, str(self.device)))
 
 
+class DeviceUtilsEqTest(DeviceUtilsTest):
+
+  def testEq_equal_deviceUtils(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
+    self.assertTrue(self.device == other)
+    self.assertTrue(other == self.device)
+
+  def testEq_equal_adbWrapper(self):
+    other = adb_wrapper.AdbWrapper('0123456789abcdef')
+    self.assertTrue(self.device == other)
+    self.assertTrue(other == self.device)
+
+  def testEq_equal_string(self):
+    other = '0123456789abcdef'
+    self.assertTrue(self.device == other)
+    self.assertTrue(other == self.device)
+
+  def testEq_devicesNotEqual(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee'))
+    self.assertFalse(self.device == other)
+    self.assertFalse(other == self.device)
+
+  def testEq_identity(self):
+    self.assertTrue(self.device == self.device)
+
+  def testEq_serialInList(self):
+    devices = [self.device]
+    self.assertTrue('0123456789abcdef' in devices)
+
+
+class DeviceUtilsLtTest(DeviceUtilsTest):
+
+  def testLt_lessThan(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff'))
+    self.assertTrue(self.device < other)
+    self.assertTrue(other > self.device)
+
+  def testLt_greaterThan_lhs(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000'))
+    self.assertFalse(self.device < other)
+    self.assertFalse(other > self.device)
+
+  def testLt_equal(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
+    self.assertFalse(self.device < other)
+    self.assertFalse(other > self.device)
+
+  def testLt_sorted(self):
+    devices = [
+        device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')),
+        device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')),
+    ]
+    sorted_devices = sorted(devices)
+    self.assertEquals('0000000000000000',
+                      sorted_devices[0].adb.GetDeviceSerial())
+    self.assertEquals('ffffffffffffffff',
+                      sorted_devices[1].adb.GetDeviceSerial())
+
+
+class DeviceUtilsStrTest(DeviceUtilsTest):
+
+  def testStr_returnsSerial(self):
+    with self.assertCalls(
+        (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
+      self.assertEqual('0123456789abcdef', str(self.device))
+
+
 class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
 
   def testIsOnline_true(self):
@@ -594,7 +661,8 @@
         (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
             temp_file),
         (self.call.adb.Shell(cmd_redirect)),
-        (self.call.device.ReadFile(temp_file.name), 'something')):
+        (self.call.device.ReadFile(temp_file.name, force_pull=True),
+         'something')):
       self.assertEquals(
           ['something'],
           self.device.RunShellCommand(
@@ -615,7 +683,8 @@
         (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
             temp_file),
         (self.call.adb.Shell(cmd_redirect)),
-        (self.call.device.ReadFile(mock.ANY), 'something')):
+        (self.call.device.ReadFile(mock.ANY, force_pull=True),
+         'something')):
       self.assertEquals(['something'],
                         self.device.RunShellCommand(cmd, check_return=True))
 
@@ -1223,6 +1292,15 @@
           self.device.ReadFile('/this/big/file/can.be.read.with.su',
                                as_root=True))
 
+  def testReadFile_forcePull(self):
+    contents = 'a' * 123456
+    with self.assertCall(
+        self.call.device._ReadFileWithPull('/read/this/big/test/file'),
+        contents):
+      self.assertEqual(
+          contents,
+          self.device.ReadFile('/read/this/big/test/file', force_pull=True))
+
 
 class DeviceUtilsWriteFileTest(DeviceUtilsTest):
 
@@ -1539,14 +1617,6 @@
           self.device.GetMemoryUsageForPid(4321))
 
 
-class DeviceUtilsStrTest(DeviceUtilsTest):
-
-  def testStr_returnsSerial(self):
-    with self.assertCalls(
-        (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
-      self.assertEqual('0123456789abcdef', str(self.device))
-
-
 class DeviceUtilsClientCache(DeviceUtilsTest):
 
   def testClientCache_twoCaches(self):
diff --git a/build/android/pylib/device/shared_prefs.py b/build/android/pylib/device/shared_prefs.py
new file mode 100644
index 0000000..32cef4b
--- /dev/null
+++ b/build/android/pylib/device/shared_prefs.py
@@ -0,0 +1,391 @@
+# 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.
+
+"""Helper object to read and modify Shared Preferences from Android apps.
+
+See e.g.:
+  http://developer.android.com/reference/android/content/SharedPreferences.html
+"""
+
+import collections
+import logging
+import posixpath
+
+from xml.etree import ElementTree
+
+
+_XML_DECLARATION = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+
+
+class BasePref(object):
+  """Base class for getting/setting the value of a specific preference type.
+
+  Should not be instantiated directly. The SharedPrefs collection will
+  instantiate the appropriate subclasses, which directly manipulate the
+  underlying xml document, to parse and serialize values according to their
+  type.
+
+  Args:
+    elem: An xml ElementTree object holding the preference data.
+
+  Properties:
+    tag_name: A string with the tag that must be used for this preference type.
+  """
+  tag_name = None
+
+  def __init__(self, elem):
+    if elem.tag != type(self).tag_name:
+      raise TypeError('Property %r has type %r, but trying to access as %r' %
+                      (elem.get('name'), elem.tag, type(self).tag_name))
+    self._elem = elem
+
+  def __str__(self):
+    """Get the underlying xml element as a string."""
+    return ElementTree.tostring(self._elem)
+
+  def get(self):
+    """Get the value of this preference."""
+    return self._elem.get('value')
+
+  def set(self, value):
+    """Set from a value casted as a string."""
+    self._elem.set('value', str(value))
+
+  @property
+  def has_value(self):
+    """Check whether the element has a value."""
+    return self._elem.get('value') is not None
+
+
+class BooleanPref(BasePref):
+  """Class for getting/setting a preference with a boolean value.
+
+  The underlying xml element has the form, e.g.:
+      <boolean name="featureEnabled" value="false" />
+  """
+  tag_name = 'boolean'
+  VALUES = {'true': True, 'false': False}
+
+  def get(self):
+    """Get the value as a Python bool."""
+    return type(self).VALUES[super(BooleanPref, self).get()]
+
+  def set(self, value):
+    """Set from a value casted as a bool."""
+    super(BooleanPref, self).set('true' if value else 'false')
+
+
+class FloatPref(BasePref):
+  """Class for getting/setting a preference with a float value.
+
+  The underlying xml element has the form, e.g.:
+      <float name="someMetric" value="4.7" />
+  """
+  tag_name = 'float'
+
+  def get(self):
+    """Get the value as a Python float."""
+    return float(super(FloatPref, self).get())
+
+
+class IntPref(BasePref):
+  """Class for getting/setting a preference with an int value.
+
+  The underlying xml element has the form, e.g.:
+      <int name="aCounter" value="1234" />
+  """
+  tag_name = 'int'
+
+  def get(self):
+    """Get the value as a Python int."""
+    return int(super(IntPref, self).get())
+
+
+class LongPref(IntPref):
+  """Class for getting/setting a preference with a long value.
+
+  The underlying xml element has the form, e.g.:
+      <long name="aLongCounter" value="1234" />
+
+  We use the same implementation from IntPref.
+  """
+  tag_name = 'long'
+
+
+class StringPref(BasePref):
+  """Class for getting/setting a preference with a string value.
+
+  The underlying xml element has the form, e.g.:
+      <string name="someHashValue">249b3e5af13d4db2</string>
+  """
+  tag_name = 'string'
+
+  def get(self):
+    """Get the value as a Python string."""
+    return self._elem.text
+
+  def set(self, value):
+    """Set from a value casted as a string."""
+    self._elem.text = str(value)
+
+
+class StringSetPref(StringPref):
+  """Class for getting/setting a preference with a set of string values.
+
+  The underlying xml element has the form, e.g.:
+      <set name="managed_apps">
+          <string>com.mine.app1</string>
+          <string>com.mine.app2</string>
+          <string>com.mine.app3</string>
+      </set>
+  """
+  tag_name = 'set'
+
+  def get(self):
+    """Get a list with the string values contained."""
+    value = []
+    for child in self._elem:
+      assert child.tag == 'string'
+      value.append(child.text)
+    return value
+
+  def set(self, value):
+    """Set from a sequence of values, each casted as a string."""
+    for child in list(self._elem):
+      self._elem.remove(child)
+    for item in value:
+      ElementTree.SubElement(self._elem, 'string').text = str(item)
+
+
+_PREF_TYPES = {c.tag_name: c for c in [BooleanPref, FloatPref, IntPref,
+                                       LongPref, StringPref, StringSetPref]}
+
+
+class SharedPrefs(object):
+  def __init__(self, device, package, filename):
+    """Helper object to read and update "Shared Prefs" of Android apps.
+
+    Such files typically look like, e.g.:
+
+        <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+        <map>
+          <int name="databaseVersion" value="107" />
+          <boolean name="featureEnabled" value="false" />
+          <string name="someHashValue">249b3e5af13d4db2</string>
+        </map>
+
+    Example usage:
+
+        prefs = shared_prefs.SharedPrefs(device, 'com.my.app', 'my_prefs.xml')
+        prefs.Load()
+        prefs.GetString('someHashValue') # => '249b3e5af13d4db2'
+        prefs.SetInt('databaseVersion', 42)
+        prefs.Remove('featureEnabled')
+        prefs.Commit()
+
+    The object may also be used as a context manager to automatically load and
+    commit, respectively, upon entering and leaving the context.
+
+    Args:
+      device: A DeviceUtils object.
+      package: A string with the package name of the app that owns the shared
+        preferences file.
+      filename: A string with the name of the preferences file to read/write.
+    """
+    self._device = device
+    self._xml = None
+    self._package = package
+    self._filename = filename
+    self._path = '/data/data/%s/shared_prefs/%s' % (package, filename)
+    self._changed = False
+
+  def __repr__(self):
+    """Get a useful printable representation of the object."""
+    return '<{cls} file {filename} for {package} on {device}>'.format(
+      cls=type(self).__name__, filename=self.filename, package=self.package,
+      device=str(self._device))
+
+  def __str__(self):
+    """Get the underlying xml document as a string."""
+    return _XML_DECLARATION + ElementTree.tostring(self.xml)
+
+  @property
+  def package(self):
+    """Get the package name of the app that owns the shared preferences."""
+    return self._package
+
+  @property
+  def filename(self):
+    """Get the filename of the shared preferences file."""
+    return self._filename
+
+  @property
+  def path(self):
+    """Get the full path to the shared preferences file on the device."""
+    return self._path
+
+  @property
+  def changed(self):
+    """True if properties have changed and a commit would be needed."""
+    return self._changed
+
+  @property
+  def xml(self):
+    """Get the underlying xml document as an ElementTree object."""
+    if self._xml is None:
+      self._xml = ElementTree.Element('map')
+    return self._xml
+
+  def Load(self):
+    """Load the shared preferences file from the device.
+
+    A empty xml document, which may be modified and saved on |commit|, is
+    created if the file does not already exist.
+    """
+    if self._device.FileExists(self.path):
+      self._xml = ElementTree.fromstring(
+          self._device.ReadFile(self.path, as_root=True))
+      assert self._xml.tag == 'map'
+    else:
+      self._xml = None
+    self._changed = False
+
+  def Clear(self):
+    """Clear all of the preferences contained in this object."""
+    if self._xml is not None and len(self): # only clear if not already empty
+      self._xml = None
+      self._changed = True
+
+  def Commit(self):
+    """Save the current set of preferences to the device.
+
+    Only actually saves if some preferences have been modified.
+    """
+    if not self.changed:
+      return
+    self._device.RunShellCommand(
+        ['mkdir', '-p', posixpath.dirname(self.path)],
+        as_root=True, check_return=True)
+    self._device.WriteFile(self.path, str(self), as_root=True)
+    self._device.KillAll(self.package, as_root=True, quiet=True)
+    self._changed = False
+
+  def __len__(self):
+    """Get the number of preferences in this collection."""
+    return len(self.xml)
+
+  def PropertyType(self, key):
+    """Get the type (i.e. tag name) of a property in the collection."""
+    return self._GetChild(key).tag
+
+  def HasProperty(self, key):
+    try:
+      self._GetChild(key)
+      return True
+    except KeyError:
+      return False
+
+  def GetBoolean(self, key):
+    """Get a boolean property."""
+    return BooleanPref(self._GetChild(key)).get()
+
+  def SetBoolean(self, key, value):
+    """Set a boolean property."""
+    self._SetPrefValue(key, value, BooleanPref)
+
+  def GetFloat(self, key):
+    """Get a float property."""
+    return FloatPref(self._GetChild(key)).get()
+
+  def SetFloat(self, key, value):
+    """Set a float property."""
+    self._SetPrefValue(key, value, FloatPref)
+
+  def GetInt(self, key):
+    """Get an int property."""
+    return IntPref(self._GetChild(key)).get()
+
+  def SetInt(self, key, value):
+    """Set an int property."""
+    self._SetPrefValue(key, value, IntPref)
+
+  def GetLong(self, key):
+    """Get a long property."""
+    return LongPref(self._GetChild(key)).get()
+
+  def SetLong(self, key, value):
+    """Set a long property."""
+    self._SetPrefValue(key, value, LongPref)
+
+  def GetString(self, key):
+    """Get a string property."""
+    return StringPref(self._GetChild(key)).get()
+
+  def SetString(self, key, value):
+    """Set a string property."""
+    self._SetPrefValue(key, value, StringPref)
+
+  def GetStringSet(self, key):
+    """Get a string set property."""
+    return StringSetPref(self._GetChild(key)).get()
+
+  def SetStringSet(self, key, value):
+    """Set a string set property."""
+    self._SetPrefValue(key, value, StringSetPref)
+
+  def Remove(self, key):
+    """Remove a preference from the collection."""
+    self.xml.remove(self._GetChild(key))
+
+  def AsDict(self):
+    """Return the properties and their values as a dictionary."""
+    d = {}
+    for child in self.xml:
+      pref = _PREF_TYPES[child.tag](child)
+      d[child.get('name')] = pref.get()
+    return d
+
+  def __enter__(self):
+    """Load preferences file from the device when entering a context."""
+    self.Load()
+    return self
+
+  def __exit__(self, exc_type, _exc_value, _traceback):
+    """Save preferences file to the device when leaving a context."""
+    if not exc_type:
+      self.Commit()
+
+  def _GetChild(self, key):
+    """Get the underlying xml node that holds the property of a given key.
+
+    Raises:
+      KeyError when the key is not found in the collection.
+    """
+    for child in self.xml:
+      if child.get('name') == key:
+        return child
+    raise KeyError(key)
+
+  def _SetPrefValue(self, key, value, pref_cls):
+    """Set the value of a property.
+
+    Args:
+      key: The key of the property to set.
+      value: The new value of the property.
+      pref_cls: A subclass of BasePref used to access the property.
+
+    Raises:
+      TypeError when the key already exists but with a different type.
+    """
+    try:
+      pref = pref_cls(self._GetChild(key))
+      old_value = pref.get()
+    except KeyError:
+      pref = pref_cls(ElementTree.SubElement(
+          self.xml, pref_cls.tag_name, {'name': key}))
+      old_value = None
+    if old_value != value:
+      pref.set(value)
+      self._changed = True
+      logging.info('Setting property: %s', pref)
diff --git a/build/android/pylib/device/shared_prefs_test.py b/build/android/pylib/device/shared_prefs_test.py
new file mode 100755
index 0000000..c5f0ec3
--- /dev/null
+++ b/build/android/pylib/device/shared_prefs_test.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# 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.
+
+"""
+Unit tests for the contents of shared_prefs.py (mostly SharedPrefs).
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import device_utils
+from pylib.device import shared_prefs
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
+
+def MockDeviceWithFiles(files=None):
+  if files is None:
+    files = {}
+
+  def file_exists(path):
+    return path in files
+
+  def write_file(path, contents, **_kwargs):
+    files[path] = contents
+
+  def read_file(path, **_kwargs):
+    return files[path]
+
+  device = mock.MagicMock(spec=device_utils.DeviceUtils)
+  device.FileExists = mock.Mock(side_effect=file_exists)
+  device.WriteFile = mock.Mock(side_effect=write_file)
+  device.ReadFile = mock.Mock(side_effect=read_file)
+  return device
+
+
+class SharedPrefsTest(unittest.TestCase):
+
+  def setUp(self):
+    self.device = MockDeviceWithFiles({
+      '/data/data/com.some.package/shared_prefs/prefs.xml':
+          "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+          '<map>\n'
+          '  <int name="databaseVersion" value="107" />\n'
+          '  <boolean name="featureEnabled" value="false" />\n'
+          '  <string name="someHashValue">249b3e5af13d4db2</string>\n'
+          '</map>'})
+    self.expected_data = {'databaseVersion': 107,
+                          'featureEnabled': False,
+                          'someHashValue': '249b3e5af13d4db2'}
+
+  def testPropertyLifetime(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    self.assertEquals(len(prefs), 0) # collection is empty before loading
+    prefs.SetInt('myValue', 444)
+    self.assertEquals(len(prefs), 1)
+    self.assertEquals(prefs.GetInt('myValue'), 444)
+    self.assertTrue(prefs.HasProperty('myValue'))
+    prefs.Remove('myValue')
+    self.assertEquals(len(prefs), 0)
+    self.assertFalse(prefs.HasProperty('myValue'))
+    with self.assertRaises(KeyError):
+      prefs.GetInt('myValue')
+
+  def testPropertyType(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    prefs.SetInt('myValue', 444)
+    self.assertEquals(prefs.PropertyType('myValue'), 'int')
+    with self.assertRaises(TypeError):
+      prefs.GetString('myValue')
+    with self.assertRaises(TypeError):
+      prefs.SetString('myValue', 'hello')
+
+  def testLoad(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    self.assertEquals(len(prefs), 0) # collection is empty before loading
+    prefs.Load()
+    self.assertEquals(len(prefs), len(self.expected_data))
+    self.assertEquals(prefs.AsDict(), self.expected_data)
+    self.assertFalse(prefs.changed)
+
+  def testClear(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    prefs.Load()
+    self.assertEquals(prefs.AsDict(), self.expected_data)
+    self.assertFalse(prefs.changed)
+    prefs.Clear()
+    self.assertEquals(len(prefs), 0) # collection is empty now
+    self.assertTrue(prefs.changed)
+
+  def testCommit(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'other_prefs.xml')
+    self.assertFalse(self.device.FileExists(prefs.path)) # file does not exist
+    prefs.Load()
+    self.assertEquals(len(prefs), 0) # file did not exist, collection is empty
+    prefs.SetInt('magicNumber', 42)
+    prefs.SetFloat('myMetric', 3.14)
+    prefs.SetLong('bigNumner', 6000000000)
+    prefs.SetStringSet('apps', ['gmail', 'chrome', 'music'])
+    self.assertFalse(self.device.FileExists(prefs.path)) # still does not exist
+    self.assertTrue(prefs.changed)
+    prefs.Commit()
+    self.assertTrue(self.device.FileExists(prefs.path)) # should exist now
+    self.device.KillAll.assert_called_once_with(prefs.package, as_root=True,
+                                                quiet=True)
+    self.assertFalse(prefs.changed)
+
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'other_prefs.xml')
+    self.assertEquals(len(prefs), 0) # collection is empty before loading
+    prefs.Load()
+    self.assertEquals(prefs.AsDict(), {
+        'magicNumber': 42,
+        'myMetric': 3.14,
+        'bigNumner': 6000000000,
+        'apps': ['gmail', 'chrome', 'music']}) # data survived roundtrip
+
+  def testAsContextManager_onlyReads(self):
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      self.assertEquals(prefs.AsDict(), self.expected_data) # loaded and ready
+    self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
+
+  def testAsContextManager_readAndWrite(self):
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      prefs.SetBoolean('featureEnabled', True)
+      prefs.Remove('someHashValue')
+      prefs.SetString('newString', 'hello')
+
+    self.assertTrue(self.device.WriteFile.called) # did write
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      # changes persisted
+      self.assertTrue(prefs.GetBoolean('featureEnabled'))
+      self.assertFalse(prefs.HasProperty('someHashValue'))
+      self.assertEquals(prefs.GetString('newString'), 'hello')
+      self.assertTrue(prefs.HasProperty('databaseVersion')) # still there
+
+  def testAsContextManager_commitAborted(self):
+    with self.assertRaises(TypeError):
+      with shared_prefs.SharedPrefs(
+          self.device, 'com.some.package', 'prefs.xml') as prefs:
+        prefs.SetBoolean('featureEnabled', True)
+        prefs.Remove('someHashValue')
+        prefs.SetString('newString', 'hello')
+        prefs.SetInt('newString', 123) # oops!
+
+    self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      # contents were not modified
+      self.assertEquals(prefs.AsDict(), self.expected_data)
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/pylib/gtest/filter/net_unittests_disabled b/build/android/pylib/gtest/filter/net_unittests_disabled
index 2632e7c..75a1c86 100644
--- a/build/android/pylib/gtest/filter/net_unittests_disabled
+++ b/build/android/pylib/gtest/filter/net_unittests_disabled
@@ -1,11 +1,5 @@
 # List of suppressions.
 
-# Bug: 171812
-MultiThreadedCertVerifierTest.CancelRequest
-
-# Bug: 380340
-SSLServerSocketTest.Handshake
-
 PythonUtils.PythonRunTime
 VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/0
 VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/1
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
index 6ce0fb1..6e332c7 100644
--- a/build/android/pylib/gtest/gtest_config.py
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -32,6 +32,7 @@
     'gpu_unittests',
     'ipc_tests',
     'media_unittests',
+    'midi_unittests',
     'net_unittests',
     'sandbox_linux_unittests',
     'skia_unittests',
diff --git a/build/android/pylib/gtest/local_device_gtest_run.py b/build/android/pylib/gtest/local_device_gtest_run.py
index fd143d6..4241e85 100644
--- a/build/android/pylib/gtest/local_device_gtest_run.py
+++ b/build/android/pylib/gtest/local_device_gtest_run.py
@@ -21,9 +21,9 @@
 _COMMAND_LINE_FLAGS_SUPPORTED = True
 
 _EXTRA_COMMAND_LINE_FILE = (
-    'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile')
+    'org.chromium.native_test.NativeTestActivity.CommandLineFile')
 _EXTRA_COMMAND_LINE_FLAGS = (
-    'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags')
+    'org.chromium.native_test.NativeTestActivity.CommandLineFlags')
 
 _MAX_SHARD_SIZE = 256
 
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py
index 44662d0..2676152 100644
--- a/build/android/pylib/gtest/setup.py
+++ b/build/android/pylib/gtest/setup.py
@@ -37,6 +37,7 @@
     'content_unittests': 'content/content_unittests.isolate',
     'media_perftests': 'media/media_perftests.isolate',
     'media_unittests': 'media/media_unittests.isolate',
+    'midi_unittests': 'media/midi/midi_unittests.isolate',
     'net_unittests': 'net/net_unittests.isolate',
     'sql_unittests': 'sql/sql_unittests.isolate',
     'sync_unit_tests': 'sync/sync_unit_tests.isolate',
diff --git a/build/android/pylib/gtest/test_package_apk.py b/build/android/pylib/gtest/test_package_apk.py
index 8da3c74..9672f7a 100644
--- a/build/android/pylib/gtest/test_package_apk.py
+++ b/build/android/pylib/gtest/test_package_apk.py
@@ -51,7 +51,7 @@
   def _GetFifo(self):
     # The test.fifo path is determined by:
     # testing/android/native_test/java/src/org/chromium/native_test/
-    #     ChromeNativeTestActivity.java and
+    #     NativeTestActivity.java and
     # testing/android/native_test_launcher.cc
     return '/data/data/' + self._package_info.package + '/files/test.fifo'
 
diff --git a/build/android/pylib/host_driven/test_case.py b/build/android/pylib/host_driven/test_case.py
index a7c6a18..6ff4c5f 100644
--- a/build/android/pylib/host_driven/test_case.py
+++ b/build/android/pylib/host_driven/test_case.py
@@ -68,9 +68,9 @@
   def SetUp(self, device, shard_index, ports_to_forward=None):
     if not ports_to_forward:
       ports_to_forward = []
-    self.device_id = device
+    self.device = device
     self.shard_index = shard_index
-    self.device = device_utils.DeviceUtils(self.device_id)
+    self.device_id = str(self.device)
     if ports_to_forward:
       self.ports_to_forward = ports_to_forward
 
@@ -117,10 +117,9 @@
     # TODO(bulach): move this to SetUp() stage.
     self.__StartForwarder()
 
-    java_test_runner = test_runner.TestRunner(self.instrumentation_options,
-                                              self.device_id,
-                                              self.shard_index, test_pkg,
-                                              additional_flags=additional_flags)
+    java_test_runner = test_runner.TestRunner(
+        self.instrumentation_options, self.device, self.shard_index,
+        test_pkg, additional_flags=additional_flags)
     try:
       java_test_runner.SetUp()
       return java_test_runner.RunTest(test)[0]
diff --git a/build/android/pylib/host_driven/test_runner.py b/build/android/pylib/host_driven/test_runner.py
index 5e175bc..8620aa1 100644
--- a/build/android/pylib/host_driven/test_runner.py
+++ b/build/android/pylib/host_driven/test_runner.py
@@ -86,7 +86,7 @@
     exception_raised = False
 
     try:
-      test.SetUp(str(self.device), self.shard_index)
+      test.SetUp(self.device, self.shard_index)
     except Exception:
       logging.exception(
           'Caught exception while trying to run SetUp() for test: ' +
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index ccc0e72..0633f14 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -30,6 +30,17 @@
 _DEFAULT_ANNOTATIONS = [
     'Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
     'EnormousTest', 'IntegrationTest']
+_EXTRA_ENABLE_HTTP_SERVER = (
+    'org.chromium.chrome.test.ChromeInstrumentationTestRunner.'
+        + 'EnableTestHttpServer')
+_EXTRA_DRIVER_TEST_LIST = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList')
+_EXTRA_DRIVER_TEST_LIST_FILE = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile')
+_EXTRA_DRIVER_TARGET_PACKAGE = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage')
+_EXTRA_DRIVER_TARGET_CLASS = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass')
 _NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE)
 _PICKLE_FORMAT_VERSION = 10
 
@@ -130,29 +141,35 @@
 
     self._apk_under_test = None
     self._package_info = None
+    self._suite = None
     self._test_apk = None
     self._test_jar = None
     self._test_package = None
     self._test_runner = None
     self._test_support_apk = None
-    self.__initializeApkAttributes(args, error_func)
+    self._initializeApkAttributes(args, error_func)
 
     self._data_deps = None
     self._isolate_abs_path = None
     self._isolate_delegate = None
     self._isolated_abs_path = None
     self._test_data = None
-    self.__initializeDataDependencyAttributes(args, isolate_delegate)
+    self._initializeDataDependencyAttributes(args, isolate_delegate)
 
     self._annotations = None
     self._excluded_annotations = None
     self._test_filter = None
-    self.__initializeTestFilterAttributes(args)
+    self._initializeTestFilterAttributes(args)
 
     self._flags = None
-    self.__initializeFlagAttributes(args)
+    self._initializeFlagAttributes(args)
 
-  def __initializeApkAttributes(self, args, error_func):
+    self._driver_apk = None
+    self._driver_package = None
+    self._driver_name = None
+    self._initializeDriverAttributes()
+
+  def _initializeApkAttributes(self, args, error_func):
     if args.apk_under_test.endswith('.apk'):
       self._apk_under_test = args.apk_under_test
     else:
@@ -164,20 +181,20 @@
       error_func('Unable to find APK under test: %s' % self._apk_under_test)
 
     if args.test_apk.endswith('.apk'):
-      test_apk_root = os.path.splitext(os.path.basename(args.test_apk))[0]
+      self._suite = os.path.splitext(os.path.basename(args.test_apk))[0]
       self._test_apk = args.test_apk
     else:
-      test_apk_root = args.test_apk
+      self._suite = args.test_apk
       self._test_apk = os.path.join(
           constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
           '%s.apk' % args.test_apk)
 
     self._test_jar = os.path.join(
         constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR,
-        '%s.jar' % test_apk_root)
+        '%s.jar' % self._suite)
     self._test_support_apk = os.path.join(
         constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR,
-        '%sSupport.apk' % test_apk_root)
+        '%sSupport.apk' % self._suite)
 
     if not os.path.exists(self._test_apk):
       error_func('Unable to find test APK: %s' % self._test_apk)
@@ -194,7 +211,7 @@
     if not self._package_info:
       logging.warning('Unable to find package info for %s', self._test_package)
 
-  def __initializeDataDependencyAttributes(self, args, isolate_delegate):
+  def _initializeDataDependencyAttributes(self, args, isolate_delegate):
     self._data_deps = []
     if args.isolate_file_path:
       self._isolate_abs_path = os.path.abspath(args.isolate_file_path)
@@ -215,7 +232,7 @@
     if not self._isolate_delegate and not self._test_data:
       logging.warning('No data dependencies will be pushed.')
 
-  def __initializeTestFilterAttributes(self, args):
+  def _initializeTestFilterAttributes(self, args):
     self._test_filter = args.test_filter
 
     def annotation_dict_element(a):
@@ -240,7 +257,7 @@
     else:
       self._excluded_annotations = {}
 
-  def __initializeFlagAttributes(self, args):
+  def _initializeFlagAttributes(self, args):
     self._flags = ['--disable-fre', '--enable-test-intents']
     # TODO(jbudorick): Transition "--device-flags" to "--device-flags-file"
     if hasattr(args, 'device_flags') and args.device_flags:
@@ -252,9 +269,17 @@
         stripped_lines = (l.strip() for l in device_flags_file)
         self._flags.extend([flag for flag in stripped_lines if flag])
 
-  @property
-  def suite(self):
-    return 'instrumentation'
+  def _initializeDriverAttributes(self):
+    self._driver_apk = os.path.join(
+        constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
+        'OnDeviceInstrumentationDriver.apk')
+    if os.path.exists(self._driver_apk):
+      self._driver_package = apk_helper.GetPackageName(
+          self._driver_apk)
+      self._driver_name = apk_helper.GetInstrumentationName(
+          self._driver_apk)
+    else:
+      self._driver_apk = None
 
   @property
   def apk_under_test(self):
@@ -265,10 +290,26 @@
     return self._flags
 
   @property
+  def driver_apk(self):
+    return self._driver_apk
+
+  @property
+  def driver_package(self):
+    return self._driver_package
+
+  @property
+  def driver_name(self):
+    return self._driver_name
+
+  @property
   def package_info(self):
     return self._package_info
 
   @property
+  def suite(self):
+    return self._suite
+
+  @property
   def test_apk(self):
     return self._test_apk
 
@@ -446,6 +487,28 @@
     return inflated_tests
 
   @staticmethod
+  def GetHttpServerEnvironmentVars():
+    return {
+      _EXTRA_ENABLE_HTTP_SERVER: None,
+    }
+
+  def GetDriverEnvironmentVars(
+      self, test_list=None, test_list_file_path=None):
+    env = {
+      _EXTRA_DRIVER_TARGET_PACKAGE: self.test_package,
+      _EXTRA_DRIVER_TARGET_CLASS: self.test_runner,
+    }
+
+    if test_list:
+      env[_EXTRA_DRIVER_TEST_LIST] = ','.join(test_list)
+
+    if test_list_file_path:
+      env[_EXTRA_DRIVER_TEST_LIST_FILE] = (
+          os.path.basename(test_list_file_path))
+
+    return env
+
+  @staticmethod
   def ParseAmInstrumentRawOutput(raw_output):
     return ParseAmInstrumentRawOutput(raw_output)
 
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index adc1037..e388fce 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -130,22 +130,41 @@
 
   #override
   def _RunTest(self, device, test):
-    test_name = self._GetTestName(test)
-    logging.info('preparing to run %s: %s' % (test_name, test))
+    extras = self._test_instance.GetHttpServerEnvironmentVars()
 
-    extras = {
-      'class': test_name,
-      'org.chromium.chrome.test.ChromeInstrumentationTestRunner'
-          '.EnableTestHttpServer': '',
-    }
-    timeout = self._GetTimeoutFromAnnotations(test['annotations'], test_name)
+    if isinstance(test, list):
+      if not self._test_instance.driver_apk:
+        raise Exception('driver_apk does not exist. '
+                        'Please build it and try again.')
+
+      def name_and_timeout(t):
+        n = self._GetTestName(t)
+        i = self._GetTimeoutFromAnnotations(t['annotations'], n)
+        return (n, i)
+
+      test_names, timeouts = zip(*(name_and_timeout(t) for t in test))
+
+      test_name = ','.join(test_names)
+      target = '%s/%s' % (
+          self._test_instance.driver_package,
+          self._test_instance.driver_name)
+      extras.update(
+          self._test_instance.GetDriverEnvironmentVars(
+              test_list=test_names))
+      timeout = sum(timeouts)
+    else:
+      test_name = self._GetTestName(test)
+      target = '%s/%s' % (
+          self._test_instance.test_package, self._test_instance.test_runner)
+      extras['class'] = test_name
+      timeout = self._GetTimeoutFromAnnotations(test['annotations'], test_name)
+
+    logging.info('preparing to run %s: %s' % (test_name, test))
 
     time_ms = lambda: int(time.time() * 1e3)
     start_ms = time_ms()
     output = device.StartInstrumentation(
-        '%s/%s' % (self._test_instance.test_package,
-                   self._test_instance.test_runner),
-        raw=True, extras=extras, timeout=timeout, retries=0)
+        target, raw=True, extras=extras, timeout=timeout, retries=0)
     duration_ms = time_ms() - start_ms
 
     # TODO(jbudorick): Make instrumentation tests output a JSON so this
diff --git a/build/android/pylib/perf/perf_control_unittest.py b/build/android/pylib/perf/perf_control_unittest.py
index dd7cb88..69b8b46 100644
--- a/build/android/pylib/perf/perf_control_unittest.py
+++ b/build/android/pylib/perf/perf_control_unittest.py
@@ -9,7 +9,6 @@
 
 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 
-from pylib import android_commands
 from pylib.device import device_utils
 from pylib.perf import perf_control
 
@@ -18,10 +17,9 @@
     if not os.getenv('BUILDTYPE'):
       os.environ['BUILDTYPE'] = 'Debug'
 
-    devices = android_commands.GetAttachedDevices()
+    devices = device_utils.DeviceUtils.HealthyDevices()
     self.assertGreater(len(devices), 0, 'No device attached!')
-    self._device = device_utils.DeviceUtils(
-        android_commands.AndroidCommands(device=devices[0]))
+    self._device = devices[0]
 
   def testHighPerfMode(self):
     perf = perf_control.PerfControl(self._device)
diff --git a/build/android/pylib/perf/setup.py b/build/android/pylib/perf/setup.py
index 8884d60..8e1fc28 100644
--- a/build/android/pylib/perf/setup.py
+++ b/build/android/pylib/perf/setup.py
@@ -10,10 +10,10 @@
 import os
 import shutil
 
-from pylib import android_commands
 from pylib import constants
 from pylib import forwarder
 from pylib.device import device_list
+from pylib.device import device_utils
 from pylib.perf import test_runner
 from pylib.utils import test_environment
 
@@ -22,10 +22,11 @@
   devices_path = os.path.join(os.environ.get('CHROMIUM_OUT_DIR', 'out'),
                               device_list.LAST_DEVICES_FILENAME)
   try:
-    devices = device_list.GetPersistentDeviceList(devices_path)
+    devices = [device_utils.DeviceUtils(s)
+               for s in device_list.GetPersistentDeviceList(devices_path)]
   except IOError as e:
     logging.error('Unable to find %s [%s]', devices_path, e)
-    devices = android_commands.GetAttachedDevices()
+    devices = device_utils.DeviceUtils.HealthyDevices()
   return sorted(devices)
 
 
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
index b69c7b2..d055ae0 100644
--- a/build/android/pylib/remote/device/remote_device_environment.py
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -78,7 +78,8 @@
     self._remote_device_minimum_os = device_json.get(
         'remote_device_minimum_os', None)
     self._remote_device_os = device_json.get('remote_device_os', None)
-    self._remote_device_timeout = device_json.get('remote_device_timeout', None)
+    self._remote_device_timeout = device_json.get(
+        'remote_device_timeout', None)
     self._results_path = device_json.get('results_path', None)
     self._runner_package = device_json.get('runner_package', None)
     self._runner_type = device_json.get('runner_type', None)
@@ -330,11 +331,6 @@
     return self._network_config
 
   @property
-  def only_output_failures(self):
-    # TODO(jbudorick): Remove this once b/18981674 is fixed.
-    return True
-
-  @property
   def results_path(self):
     return self._results_path
 
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py
index 973eebe..ec747f1 100644
--- a/build/android/pylib/remote/device/remote_device_gtest_run.py
+++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -17,18 +17,14 @@
 
 
 _EXTRA_COMMAND_LINE_FILE = (
-    'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile')
-# TODO(jbudorick): Remove this extra when b/18981674 is fixed.
-_EXTRA_ONLY_OUTPUT_FAILURES = (
-    'org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner.'
-        'OnlyOutputFailures')
+    'org.chromium.native_test.NativeTestActivity.CommandLineFile')
 
 
 class RemoteDeviceGtestTestRun(remote_device_test_run.RemoteDeviceTestRun):
   """Run gtests and uirobot tests on a remote device."""
 
   DEFAULT_RUNNER_PACKAGE = (
-      'org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner')
+      'org.chromium.native_test.NativeTestInstrumentationTestRunner')
 
   #override
   def TestPackage(self):
@@ -61,8 +57,6 @@
         env_vars[_EXTRA_COMMAND_LINE_FILE] = os.path.basename(flag_file.name)
         self._test_instance._data_deps.append(
             (os.path.abspath(flag_file.name), None))
-      if self._env.only_output_failures:
-        env_vars[_EXTRA_ONLY_OUTPUT_FAILURES] = None
       self._AmInstrumentTestSetup(
           dummy_app_path, self._test_instance.apk, runner_package,
           environment_variables=env_vars)
@@ -73,15 +67,13 @@
   def _ParseTestResults(self):
     logging.info('Parsing results from stdout.')
     results = base_test_result.TestRunResults()
-    output = self._results['results']['output'].splitlines()
+    output = self._GetRawTestOutput().splitlines()
     output = (l[len(self._INSTRUMENTATION_STREAM_LEADER):] for l in output
               if l.startswith(self._INSTRUMENTATION_STREAM_LEADER))
     results_list = self._test_instance.ParseGTestOutput(output)
     results.AddResults(results_list)
-    if self._env.only_output_failures:
-      logging.info('See logcat for more results information.')
     if not self._results['results']['pass']:
       results.AddResult(base_test_result.BaseTestResult(
           'Remote Service detected error.',
           base_test_result.ResultType.FAIL))
-    return results
\ No newline at end of file
+    return results
diff --git a/build/android/pylib/remote/device/remote_device_helper.py b/build/android/pylib/remote/device/remote_device_helper.py
index 5b1411e..896ae99 100644
--- a/build/android/pylib/remote/device/remote_device_helper.py
+++ b/build/android/pylib/remote/device/remote_device_helper.py
@@ -20,4 +20,5 @@
       error_msg: Error message to display if bad response is seen.
   """
   if response.status_code != 200:
-    raise RemoteDeviceError(error_msg)
+    raise RemoteDeviceError(
+        '%s (%d: %s)' % (error_msg, response.status_code, response.reason))
diff --git a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
index fe173a4..0b0afb1 100644
--- a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
@@ -8,6 +8,7 @@
 import os
 import tempfile
 
+from pylib import constants
 from pylib.base import base_test_result
 from pylib.remote.device import remote_device_test_run
 from pylib.utils import apk_helper
@@ -25,9 +26,33 @@
   def _TriggerSetUp(self):
     """Set up the triggering of a test run."""
     logging.info('Triggering test run.')
-    self._AmInstrumentTestSetup(
-        self._test_instance._apk_under_test, self._test_instance.test_apk,
-        self._test_instance.test_runner, environment_variables={})
+
+    with tempfile.NamedTemporaryFile(suffix='.txt') as test_list_file:
+      tests = self._test_instance.GetTests()
+      logging.debug('preparing to run %d instrumentation tests remotely:',
+                    len(tests))
+      for t in tests:
+        test_name = '%s#%s' % (t['class'], t['method'])
+        logging.debug('  %s', test_name)
+        test_list_file.write('%s\n' % test_name)
+      test_list_file.flush()
+      self._test_instance._data_deps.append(
+          (os.path.abspath(test_list_file.name), None))
+
+      env_vars = self._test_instance.GetDriverEnvironmentVars(
+          test_list_file_path=test_list_file.name)
+      env_vars.update(self._test_instance.GetHttpServerEnvironmentVars())
+
+      logging.debug('extras:')
+      for k, v in env_vars.iteritems():
+        logging.debug('  %s: %s', k, v)
+
+      self._AmInstrumentTestSetup(
+          self._test_instance.apk_under_test,
+          self._test_instance.driver_apk,
+          self._test_instance.driver_name,
+          environment_variables=env_vars,
+          extra_apks=[self._test_instance.test_apk])
 
   #override
   def _ParseTestResults(self):
@@ -35,7 +60,7 @@
     r = base_test_result.TestRunResults()
     result_code, result_bundle, statuses = (
         self._test_instance.ParseAmInstrumentRawOutput(
-            self._results['results']['output'].splitlines()))
+            self._GetRawTestOutput().splitlines()))
     result = self._test_instance.GenerateTestResults(
         result_code, result_bundle, statuses, 0, 0)
 
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py
index 7aa91ae..60a0664 100644
--- a/build/android/pylib/remote/device/remote_device_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -29,6 +29,8 @@
   COMPLETE = 'complete'
   HEARTBEAT_INTERVAL = 300
 
+  _RESULTS_FILE = 'appurify_results/result.txt'
+
   def __init__(self, env, test_instance):
     """Constructor.
 
@@ -173,7 +175,7 @@
     """Download the test results from remote device service.
 
     Args:
-      results_path: path to download results to.
+      results_path: Path to download appurify results zipfile.
     """
     if results_path:
       logging.info('Downloading results to %s.' % results_path)
@@ -184,6 +186,21 @@
         appurify_sanitized.utils.wget(self._results['results']['url'],
                                       results_path)
 
+  def _GetRawTestOutput(self):
+    """Returns the test output."""
+    # TODO(mikecase): Remove getting results from zip when b/18981674 is fixed.
+    results_zipfile = self._env.results_path
+    if results_zipfile and os.path.exists(results_zipfile):
+      with zipfile.ZipFile(results_zipfile) as z:
+        with z.open(self._RESULTS_FILE, 'r') as r:
+          return r.read()
+    else:
+      logging.warning(
+          'If the test output is too long, some test results may get cut off.')
+      logging.warning(
+          'Use the --results-path option to ensure you get the full results.')
+      return self._results['results']['output']
+
   def _GetTestStatus(self, test_run_id):
     """Checks the state of the test, and sets self._results
 
@@ -201,7 +218,7 @@
     return self._results['status']
 
   def _AmInstrumentTestSetup(self, app_path, test_path, runner_package,
-                             environment_variables):
+                             environment_variables, extra_apks=None):
     config = {'runner': runner_package}
     if environment_variables:
       config['environment_vars'] = ','.join(
@@ -213,6 +230,7 @@
     if data_deps:
       with tempfile.NamedTemporaryFile(suffix='.zip') as test_with_deps:
         sdcard_files = []
+        additional_apks = []
         host_test = os.path.basename(test_path)
         with zipfile.ZipFile(test_with_deps.name, 'w') as zip_file:
           zip_file.write(test_path, host_test, zipfile.ZIP_DEFLATED)
@@ -223,8 +241,14 @@
             else:
               zip_utils.WriteToZipFile(zip_file, h, os.path.basename(h))
               sdcard_files.append(os.path.basename(h))
+          for a in extra_apks or ():
+            zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a));
+            additional_apks.append(os.path.basename(a))
+
         config['sdcard_files'] = ','.join(sdcard_files)
         config['host_test'] = host_test
+        if additional_apks:
+          config['additional_apks'] = ','.join(additional_apks)
         self._test_id = self._UploadTestToDevice(
             'robotium', test_with_deps.name, app_id=self._app_id)
     else:
@@ -238,7 +262,8 @@
 
   def _UploadAppToDevice(self, app_path):
     """Upload app to device."""
-    logging.info('Uploading %s to remote service.', app_path)
+    logging.info('Uploading %s to remote service as %s.', app_path,
+                 self._test_instance.suite)
     with open(app_path, 'rb') as apk_src:
       with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
                                               logging.WARNING):
@@ -297,4 +322,4 @@
         config_response = appurify_sanitized.api.config_upload(
             self._env.token, config, self._test_id)
       remote_device_helper.TestHttpResponse(
-          config_response, 'Unable to upload test config.')
\ No newline at end of file
+          config_response, 'Unable to upload test config.')
diff --git a/build/android/pylib/utils/emulator.py b/build/android/pylib/utils/emulator.py
index 26b9109..635462f 100644
--- a/build/android/pylib/utils/emulator.py
+++ b/build/android/pylib/utils/emulator.py
@@ -15,7 +15,6 @@
 import time
 
 # TODO(craigdh): Move these pylib dependencies to pylib/utils/.
-from pylib import android_commands
 from pylib import cmd_helper
 from pylib import constants
 from pylib import pexpect
@@ -90,14 +89,14 @@
   running but a device slot is taken.  A little bot trouble and and
   we're out of room forever.
   """
-  emulators = android_commands.GetAttachedDevices(hardware=False)
+  emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
   if not emulators:
     return
-  for emu_name in emulators:
-    cmd_helper.RunCmd(['adb', '-s', emu_name, 'emu', 'kill'])
+  for e in emulators:
+    e.adb.Emu(['kill'])
   logging.info('Emulator killing is async; give a few seconds for all to die.')
   for _ in range(5):
-    if not android_commands.GetAttachedDevices(hardware=False):
+    if not any(d.adb.is_emulator for d in device_utils.HealthyDevices()):
       return
     time.sleep(1)
 
@@ -141,9 +140,9 @@
 def _GetAvailablePort():
   """Returns an available TCP port for the console."""
   used_ports = []
-  emulators = android_commands.GetAttachedDevices(hardware=False)
+  emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
   for emulator in emulators:
-    used_ports.append(emulator.split('-')[1])
+    used_ports.append(emulator.adb.GetDeviceSerial().split('-')[1])
   for port in PortPool.port_range():
     if str(port) not in used_ports:
       return port
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
index 90d5ca0..cac39d8 100644
--- a/build/android/pylib/utils/isolator.py
+++ b/build/android/pylib/utils/isolator.py
@@ -36,6 +36,7 @@
     'enable_plugins': '0',
     'fastbuild': '0',
     'icu_use_data_file_flag': '1',
+    'kasko': '0',
     'lsan': '0',
     'msan': '0',
     # TODO(maruel): This may not always be true.
diff --git a/build/android/pylib/utils/md5sum.py b/build/android/pylib/utils/md5sum.py
index 4d7d0b0..d59245c 100644
--- a/build/android/pylib/utils/md5sum.py
+++ b/build/android/pylib/utils/md5sum.py
@@ -34,9 +34,11 @@
   if isinstance(paths, basestring):
     paths = [paths]
 
-  out = cmd_helper.GetCmdOutput(
-      [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host')] +
-          [p for p in paths])
+  md5sum_bin_host_path = os.path.join(
+      constants.GetOutDirectory(), 'md5sum_bin_host')
+  if not os.path.exists(md5sum_bin_host_path):
+    raise IOError('File not built: %s' % md5sum_bin_host_path)
+  out = cmd_helper.GetCmdOutput([md5sum_bin_host_path] + [p for p in paths])
 
   return _ParseMd5SumOutput(out.splitlines())
 
@@ -53,9 +55,10 @@
     paths = [paths]
 
   if not device.FileExists(MD5SUM_DEVICE_BIN_PATH):
-    device.adb.Push(
-        os.path.join(constants.GetOutDirectory(), 'md5sum_dist'),
-        MD5SUM_DEVICE_LIB_PATH)
+    md5sum_dist_path = os.path.join(constants.GetOutDirectory(), 'md5sum_dist')
+    if not os.path.exists(md5sum_dist_path):
+      raise IOError('File not built: %s' % md5sum_dist_path)
+    device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
 
   out = []
 
diff --git a/build/android/pylib/utils/md5sum_test.py b/build/android/pylib/utils/md5sum_test.py
index de9cd35..5bdee32 100755
--- a/build/android/pylib/utils/md5sum_test.py
+++ b/build/android/pylib/utils/md5sum_test.py
@@ -24,6 +24,8 @@
     self._patchers = [
         mock.patch('pylib.constants.GetOutDirectory',
                    new=mock.Mock(return_value=TEST_OUT_DIR)),
+        mock.patch('os.path.exists',
+                   new=mock.Mock(return_value=True)),
     ]
     for p in self._patchers:
       p.start()
diff --git a/build/android/setup.gyp b/build/android/setup.gyp
index 7dce19d..b3c3422 100644
--- a/build/android/setup.gyp
+++ b/build/android/setup.gyp
@@ -16,7 +16,7 @@
             {
               'destination': '<(SHARED_LIB_DIR)/',
               'files': [
-                '<(android_stlport_libs_dir)/libstlport_shared.so',
+                '<(android_libcpp_libs_dir)/libc++_shared.so',
               ],
             },
           ],
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index c54ed28..b9d2a3f 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -16,7 +16,6 @@
 import threading
 import unittest
 
-from pylib import android_commands
 from pylib import constants
 from pylib import forwarder
 from pylib import ports
@@ -25,6 +24,8 @@
 from pylib.base import test_dispatcher
 from pylib.base import test_instance_factory
 from pylib.base import test_run_factory
+from pylib.device import device_errors
+from pylib.device import device_utils
 from pylib.gtest import gtest_config
 from pylib.gtest import setup as gtest_setup
 from pylib.gtest import test_options as gtest_test_options
@@ -110,7 +111,7 @@
   if args.build_directory:
     constants.SetBuildDirectory(args.build_directory)
   if args.output_directory:
-    constants.SetOutputDirectort(args.output_directory)
+    constants.SetOutputDirectory(args.output_directory)
   if args.adb_path:
     constants.SetAdbPath(args.adb_path)
   # Some things such as Forwarder require ADB to be in the environment path.
@@ -867,18 +868,19 @@
   Returns:
     A list of attached devices.
   """
-  attached_devices = []
-
-  attached_devices = android_commands.GetAttachedDevices()
+  attached_devices = device_utils.DeviceUtils.HealthyDevices()
   if test_device:
-    assert test_device in attached_devices, (
-        'Did not find device %s among attached device. Attached devices: %s'
-        % (test_device, ', '.join(attached_devices)))
-    attached_devices = [test_device]
+    test_device = [d for d in attached_devices if d == test_device]
+    if not test_device:
+      raise device_errors.DeviceUnreachableError(
+          'Did not find device %s among attached device. Attached devices: %s'
+          % (test_device, ', '.join(attached_devices)))
+    return test_device
 
-  assert attached_devices, 'No devices attached.'
-
-  return sorted(attached_devices)
+  else:
+    if not attached_devices:
+      raise device_errors.NoDevicesError()
+    return sorted(attached_devices)
 
 
 def RunTestsCommand(args, parser):
diff --git a/build/apk_test.gypi b/build/apk_test.gypi
index 792d92c..3a66e3b 100644
--- a/build/apk_test.gypi
+++ b/build/apk_test.gypi
@@ -22,6 +22,7 @@
     '<(DEPTH)/base/base.gyp:base_java',
     '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
     '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk',
+    '<(DEPTH)/testing/android/appurify_support.gyp:appurify_support_java',
     '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
   ],
   'conditions': [
diff --git a/build/common.gypi b/build/common.gypi
index c5a8fac..a406248 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -173,6 +173,7 @@
 
         # The system root for cross-compiles. Default: none.
         'sysroot%': '',
+        'use_sysroot%': 0,
         'chroot_cmd%': '',
 
         # The system libdir used for this ABI.
@@ -416,9 +417,6 @@
       # See https://code.google.com/p/sawbuck/wiki/SyzyASanHowTo
       'syzyasan%': 0,
 
-      # Enable crash reporting via Kasko.
-      'kasko%': 0,
-
       # Enable building with LSan (Clang's -fsanitize=leak option).
       # -fsanitize=leak only works with clang, but lsan=1 implies clang=1
       # See https://sites.google.com/a/chromium.org/dev/developers/testing/leaksanitizer
@@ -941,7 +939,7 @@
           'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_arm-sysroot',
         }], # OS=="linux" and target_arch=="arm" and chromeos==0
 
-        ['OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0', {
+        ['OS=="linux" and ((branding=="Chrome" and buildtype=="Official" and chromeos==0) or use_sysroot==1)' , {
           'conditions': [
             ['target_arch=="x64"', {
               'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_amd64-sysroot',
@@ -1011,6 +1009,15 @@
         }, {
           'sas_dll_path%': '<(DEPTH)/third_party/platformsdk_win7/files/redist/x86',
         }],
+
+        # Enable crash reporting via Kasko.
+        ['OS=="win" and target_arch=="ia32"', {
+          # TODO(erikwright): This should be disabled after a single ship on Canary channel.
+          'kasko%': 1,
+        }, {
+          'kasko%': 0,
+        }],
+
       ],
 
       # Setting this to '0' will cause V8's startup snapshot to be
@@ -1688,7 +1695,7 @@
           'android_ndk_absolute_root%': '<(android_ndk_absolute_root)',
           'android_sdk_root%': '<(android_sdk_root)',
           'android_sdk_version%': '<(android_sdk_version)',
-          'android_stlport_root': '<(android_ndk_root)/sources/cxx-stl/stlport',
+          'android_libcpp_root': '<(android_ndk_root)/sources/cxx-stl/llvm-libc++',
           'host_os%': '<(host_os)',
 
           'android_sdk%': '<(android_sdk_root)/platforms/android-<(android_sdk_version)',
@@ -1764,9 +1771,9 @@
         'android_sdk%': '<(android_sdk)',
         'android_sdk_jar%': '<(android_sdk)/android.jar',
 
-        'android_stlport_root': '<(android_stlport_root)',
-        'android_stlport_include': '<(android_stlport_root)/stlport',
-        'android_stlport_libs_dir': '<(android_stlport_root)/libs/<(android_app_abi)',
+        'android_libcpp_root': '<(android_libcpp_root)',
+        'android_libcpp_include': '<(android_libcpp_root)/libcxx/include',
+        'android_libcpp_libs_dir': '<(android_libcpp_root)/libs/<(android_app_abi)',
         'host_os%': '<(host_os)',
 
         # Location of the "objcopy" binary, used by both gyp and scripts.
@@ -1929,9 +1936,14 @@
           },{
             'winsdk_arch%': '<(target_arch)',
           }],
-          ['component=="shared_library"', {
+          ['component=="shared_library" or MSVS_VERSION == "2015"', {
+            # TODO(scottmg): The allocator shimming doesn't work on the 2015 CRT
+            # and we are hoping to be able to remove it if an additional feature
+            # lands in the 2015 CRT API. For now, don't shim and revisit once
+            # VS2015 is RTM: http://crbug.com/481611.
             'win_use_allocator_shim%': 0,
-          },{
+          }],
+          ['component=="static_library"', {
             # Turn on multiple dll by default on Windows when in static_library.
             'chrome_multiple_dll%': 1,
           }],
@@ -2168,17 +2180,23 @@
                 ],
               },
               'clang_dynlib_flags%': '-Xclang -load -Xclang <(clang_lib_path) ',
+              'clang_plugin_args%': '',
             }, { # OS == "win"
               # On Windows, the plugin is built directly into clang, so there's
               # no need to load it dynamically.
               'clang_dynlib_flags%': '',
+
+              # Don't error on plugin warnings on Windows until pre-existing warnings
+              # are cleaned up.  https://crbug.com/467287
+              'clang_plugin_args%': '-Xclang -plugin-arg-find-bad-constructs -Xclang warn-only',
             }]
           ],
         },
         # If you change these, also change build/config/clang/BUILD.gn.
         'clang_chrome_plugins_flags%':
           '<(clang_dynlib_flags)'
-          '-Xclang -add-plugin -Xclang find-bad-constructs',
+          '-Xclang -add-plugin -Xclang find-bad-constructs '
+          '<(clang_plugin_args)',
       }],
       ['asan==1 or msan==1 or lsan==1 or tsan==1', {
         'clang%': 1,
@@ -4085,9 +4103,6 @@
                     'cflags!': [
                        '-fstack-protector',  # stack protector is always enabled on arm64.
                     ],
-                    'ldflags': [
-                      '-fuse-ld=gold',
-                    ],
                   }],
                 ],
               }],
@@ -4630,9 +4645,9 @@
           # Figure this out early since it needs symbols from libgcc.a, so it
           # has to be before that in the set of libraries.
           ['component=="shared_library"', {
-              'android_stlport_library': 'stlport_shared',
+              'android_libcpp_library': 'c++_shared',
           }, {
-              'android_stlport_library': 'stlport_static',
+              'android_libcpp_library': 'c++_static',
           }],
         ],
 
@@ -4712,17 +4727,17 @@
               '-finline-limit=64',
               '<@(release_extra_cflags)',
               '--sysroot=<(android_ndk_sysroot)',
-              # NOTE: The stlport header include paths below are specified in
+              # NOTE: The libc++ header include paths below are specified in
               # cflags rather than include_dirs because they need to come
               # after include_dirs.
               # The include ordering here is important; change with caution.
-              '-isystem<(android_stlport_include)',
+              '-isystem<(android_libcpp_include)',
+              '-isystem<(android_ndk_root)/sources/cxx-stl/llvm-libc++abi/libcxxabi/include',
+              '-isystem<(android_ndk_root)/sources/android/support/include',
             ],
             'defines': [
               'ANDROID',
               '__GNU_SOURCE=1',  # Necessary for clone()
-              'USE_STLPORT=1',
-              '_STLP_USE_PTR_SPECIALIZATIONS=1',
               'CHROME_BUILD_ID="<(chrome_build_id)"',
               # The NDK has these things, but doesn't define the constants
               # to say that it does. Define them here instead.
@@ -4735,11 +4750,11 @@
               '-Wl,--no-undefined',
               '--sysroot=<(android_ndk_sysroot)',
               '-nostdlib',
-              '-L<(android_stlport_libs_dir)',
-              # Don't allow visible symbols from libgcc or stlport to be
+              '-L<(android_libcpp_libs_dir)',
+              # Don't allow visible symbols from libgcc or libc++ to be
               # re-exported.
               '-Wl,--exclude-libs=libgcc.a',
-              '-Wl,--exclude-libs=libstlport_static.a',
+              '-Wl,--exclude-libs=libc++_static.a',
               # Don't allow visible symbols from libraries that contain
               # assembly code with symbols that aren't hidden properly.
               # http://crbug.com/448386
@@ -4752,7 +4767,8 @@
               '-Wl,--exclude-libs=libvpx.a',
             ],
             'libraries': [
-              '-l<(android_stlport_library)',
+              '-l<(android_libcpp_library)',
+              '-latomic',
               # Manually link the libgcc.a that the cross compiler uses.
               '<!(<(android_toolchain)/*-gcc -print-libgcc-file-name)',
               '-lc',
@@ -4772,6 +4788,11 @@
                 ],
               }],
               ['clang==1', {
+                'libraries!': [
+                  # Clang with libc++ does not require an explicit atomic
+                  # library reference.
+                  '-latomic',
+                ],
                 'cflags': [
                   # Work around incompatibilities between bionic and clang
                   # headers.
@@ -5119,6 +5140,22 @@
             }],
           ],
         },
+        'configurations': {
+          'Release_Base': {
+            'conditions': [
+              ['branding=="Chrome" and buildtype=="Official"', {
+                'xcode_settings': {
+                  'OTHER_CFLAGS': [
+                    # The Google Chrome Framework dSYM generated by dsymutil has
+                    # grown larger than 4GB, which dsymutil can't handle. Reduce
+                    # the amount of debug symbols.
+                    '-fno-standalone-debug',  # See http://crbug.com/479841
+                  ]
+                },
+              }],
+            ],
+          },  # configuration "Release"
+        },  # configurations
         'xcode_settings': {
           'GCC_DYNAMIC_NO_PIC': 'NO',               # No -mdynamic-no-pic
                                                     # (Equivalent to -fPIC)
@@ -5136,16 +5173,6 @@
             # specified or not.
             '-fno-strict-aliasing',  # See http://crbug.com/32204.
           ],
-          'conditions': [
-            ['branding=="Chrome" and buildtype=="Official"', {
-              'OTHER_CFLAGS': [
-                # The Google Chrome Framework dSYM generated by dsymutil has
-                # grown larger than 4GB, which dsymutil can't handle. Reduce
-                # the amount of debug symbols.
-                '-gline-tables-only',  # See http://crbug.com/479841
-              ]
-            }],
-          ],
         },
         'target_conditions': [
           ['_type=="executable"', {
@@ -5769,13 +5796,20 @@
                     'AdditionalOptions': [
                       '-fsanitize-coverage=<(sanitizer_coverage)',
                     ],
-                    'defines': [
-                      'SANITIZER_COVERAGE',
-                    ],
                   },
                 }],
               ],
             },
+            'conditions': [
+              ['sanitizer_coverage!=0', {
+                # TODO(asan/win): Move this down into the general
+                # win-target_defaults section once the 64-bit asan runtime
+                # exists.  See crbug.com/345874.
+                'defines': [
+                  'SANITIZER_COVERAGE',
+                ],
+              }],
+            ],
           },
           'x64_Base': {
             'msvs_settings': {
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 22cb45a..1bd666b 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/allocator.gni")
+import("//build/config/chrome_build.gni")
 import("//build/config/crypto.gni")
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 455ec0d..2274c0e 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -66,11 +66,13 @@
   # Selects the desired build flavor. Official builds get additional
   # processing to prepare for release. Normally you will want to develop and
   # test with this flag off.
+  # TODO(brettw) move to chrome_build.gni when DEPS are updated.
   is_official_build = false
 
   # Select the desired branding flavor. False means normal Chromium branding,
   # true means official Google Chrome branding (requires extra Google-internal
   # resources).
+  # TODO(brettw) move to chrome_build.gni when DEPS are updated.
   is_chrome_branded = false
 
   # Compile for Address Sanitizer to find memory bugs.
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 77ee311..093e8b3 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -157,12 +157,12 @@
   android_gdbserver =
       "$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver"
 
-  # stlport stuff --------------------------------------------------------------
+  # libc++ stuff ---------------------------------------------------------------
 
   if (component_mode == "shared_library") {
-    android_stlport_library = "stlport_shared"
+    android_libcpp_library = "c++_shared"
   } else {
-    android_stlport_library = "stlport_static"
+    android_libcpp_library = "c++_static"
   }
 
   # ABI ------------------------------------------------------------------------
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 39b2f39..b1b23b0 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1555,8 +1555,8 @@
   android_apk(target_name) {
     final_apk_path = "$root_build_dir/${apk_name}_apk/${apk_name}-debug.apk"
     java_files = [
-      "//testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java",
-      "//testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java",
+      "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java",
+      "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
     ]
     android_manifest = "//testing/android/native_test/java/AndroidManifest.xml"
     native_libs = [ unittests_binary ]
@@ -1566,6 +1566,7 @@
     deps = [
       "//base:base_java",
       "//build/android/pylib/remote/device/dummy:remote_device_dummy_apk",
+      "//testing/android/appurify_support:appurify_support_java",
     ]
     if (defined(invoker.deps)) {
       deps += invoker.deps
diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni
new file mode 100644
index 0000000..e2ff123
--- /dev/null
+++ b/build/config/chrome_build.gni
@@ -0,0 +1,22 @@
+# 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.
+
+declare_args() {
+  # Selects the desired build flavor. Official builds get additional
+  # processing to prepare for release. Normally you will want to develop and
+  # test with this flag off.
+  # TODO(brettw) move here from BUILDCONFIG.gn when DEPS are updated.
+  #is_official_build = false
+
+  # Select the desired branding flavor. False means normal Chromium branding,
+  # true means official Google Chrome branding (requires extra Google-internal
+  # resources).
+  # TODO(brettw) move here from BUILDCONFIG.gn when DEPS are updated.
+  #is_chrome_branded = false
+
+  # Break chrome.dll into multple pieces based on process type. Only available
+  # on Windows.
+  # TODO(brettw) make this work. When it does, the declaration should be:
+  is_multi_dll_chrome = is_win && !is_component_build
+}
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
index 3d96500..e79a7b9 100644
--- a/build/config/clang/BUILD.gn
+++ b/build/config/clang/BUILD.gn
@@ -31,6 +31,16 @@
       ]
     }
 
+    if (is_win) {
+      # Don't error on plugin warnings on Windows until pre-existing warnings
+      # are cleaned up.  https://crbug.com/467287
+      cflags += [
+        "-Xclang",
+        "-plugin-arg-find-bad-constructs",
+        "-Xclang warn-only",
+      ]
+    }
+
     cflags += [
       "-Xclang",
       "-add-plugin",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index c217154..ad94705 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/android/config.gni")
+import("//build/config/chrome_build.gni")
 if (current_cpu == "arm") {
   import("//build/config/arm.gni")
 }
@@ -461,10 +462,10 @@
     ldflags += [
       "-Wl,--no-undefined",
 
-      # Don't allow visible symbols from libgcc or stlport to be
+      # Don't allow visible symbols from libgcc or libc++ to be
       # re-exported.
       "-Wl,--exclude-libs=libgcc.a",
-      "-Wl,--exclude-libs=libstlport_static.a",
+      "-Wl,--exclude-libs=libc++_static.a",
 
       # Don't allow visible symbols from libraries that contain
       # assembly code with symbols that aren't hidden properly.
@@ -546,7 +547,7 @@
     ]
   }
 
-  # Stlport setup. Android uses a different (smaller) version of the STL.
+  # Android standard library setup.
   if (is_android) {
     if (is_clang) {
       # Work around incompatibilities between bionic and clang headers.
@@ -556,11 +557,7 @@
       ]
     }
 
-    defines += [
-      "USE_STLPORT=1",
-      "_STLP_USE_PTR_SPECIALIZATIONS=1",
-      "__GNU_SOURCE=1",  # Necessary for clone().
-    ]
+    defines += [ "__GNU_SOURCE=1" ]  # Necessary for clone().
 
     # TODO(jdduke) Re-enable on mips after resolving linking
     # issues with libc++ (crbug.com/456380).
@@ -569,45 +566,48 @@
     }
     ldflags += [ "-nostdlib" ]
 
-    # NOTE: The stlport header include paths below are specified in cflags
+    # NOTE: The libc++ header include paths below are specified in cflags
     # rather than include_dirs because they need to come after include_dirs.
     # Think of them like system headers, but don't use '-isystem' because the
     # arm-linux-androideabi-4.4.3 toolchain (circa Gingerbread) will exhibit
     # strange errors. The include ordering here is important; change with
     # caution.
-    android_stlport_root = "$android_ndk_root/sources/cxx-stl/stlport"
+    android_libcpp_root = "$android_ndk_root/sources/cxx-stl/llvm-libc++"
 
-    cflags += [ "-isystem" +
-                rebase_path("$android_stlport_root/stlport", root_build_dir) ]
-    lib_dirs += [ "$android_stlport_root/libs/$android_app_abi" ]
+    cflags += [
+      "-isystem" +
+          rebase_path("$android_libcpp_root/libcxx/include", root_build_dir),
+      "-isystem" + rebase_path(
+              "$android_ndk_root/sources/cxx-stl/llvm-libc++abi/libcxxabi/include",
+              root_build_dir),
+      "-isystem" +
+          rebase_path("$android_ndk_root/sources/android/support/include",
+                      root_build_dir),
+    ]
+
+    lib_dirs += [ "$android_libcpp_root/libs/$android_app_abi" ]
 
     if (component_mode == "shared_library") {
-      libs += [ "stlport_shared" ]
+      android_libcpp_library = "c++_shared"
     } else {
-      libs += [ "stlport_static" ]
-    }
-
-    if (current_cpu == "mipsel") {
-      libs += [
-        # ld linker is used for mips Android, and ld does not accept library
-        # absolute path prefixed by "-l"; Since libgcc does not exist in mips
-        # sysroot the proper library will be linked.
-        # TODO(gordanac): Remove once gold linker is used for mips Android.
-        "gcc",
-      ]
-    } else {
-      libs += [
-        # Manually link the libgcc.a that the cross compiler uses. This is
-        # absolute because the linker will look inside the sysroot if it's not.
-        rebase_path(android_libgcc_file),
-      ]
+      android_libcpp_library = "c++_static"
     }
 
     libs += [
+      "$android_libcpp_library",
+
+      # Manually link the libgcc.a that the cross compiler uses. This is
+      # absolute because the linker will look inside the sysroot if it's not.
+      rebase_path(android_libgcc_file),
       "c",
       "dl",
       "m",
     ]
+
+    # Clang with libc++ does not require an explicit atomic library reference.
+    if (!is_clang) {
+      libs += [ "atomic" ]
+    }
   }
 }
 
diff --git a/build/config/features.gni b/build/config/features.gni
index dd7b081..290c1d6 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -11,6 +11,7 @@
 #
 # See also build/config/ui.gni
 
+import("//build/config/chrome_build.gni")
 if (is_android) {
   import("//build/config/android/config.gni")
 }
@@ -32,8 +33,8 @@
   # the commented out logic.
   # Eventually we want this to be:
   #   enable_nacl = !is_ios && !is_android
-  enable_nacl =
-      (is_linux && !is_chromeos && !is_debug && current_cpu == "x64") || is_nacl
+  enable_nacl = (is_linux && !is_chromeos && !is_component_build &&
+                 current_cpu == "x64") || is_nacl
   enable_nacl_untrusted = enable_nacl
   enable_pnacl = enable_nacl_untrusted
 
@@ -84,6 +85,20 @@
   # Enables browser side Content Decryption Modules. Required for embedders
   # (e.g. Android and ChromeCast) that use a browser side CDM.
   enable_browser_cdms = is_android
+
+  # Variable safe_browsing is used to control the build time configuration for
+  # safe browsing feature. Safe browsing can be compiled in 3 different levels:
+  # 0 disables it, 1 enables it fully, and 2 enables only UI and reporting
+  # features without enabling phishing and malware detection. This is useful to
+  # integrate a third party phishing/malware detection to existing safe browsing
+  # logic.
+  if (is_android) {
+    safe_browsing_mode = 2
+  } else if (is_ios) {
+    safe_browsing_mode = 0
+  } else {
+    safe_browsing_mode = 1
+  }
 }
 
 # Additional dependent variables -----------------------------------------------
@@ -133,19 +148,6 @@
 
 enable_extensions = !is_android && !is_ios
 
-# Variable safe_browsing is used to control the build time configuration for
-# safe browsing feature. Safe browsing can be compiled in 3 different levels: 0
-# disables it, 1 enables it fully, and 2 enables only UI and reporting features
-# without enabling phishing and malware detection. This is useful to integrate
-# a third party phishing/malware detection to existing safe browsing logic.
-if (is_android) {
-  safe_browsing_mode = 2
-} else if (is_ios) {
-  safe_browsing_mode = 0
-} else {
-  safe_browsing_mode = 1
-}
-
 enable_task_manager = !is_ios && !is_android
 
 use_cups = is_desktop_linux || is_mac
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
index 44995a3..600085e 100644
--- a/build/config/mac/mac_sdk.gni
+++ b/build/config/mac/mac_sdk.gni
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chrome_build.gni")
+
 declare_args() {
   # Minimum supported version of the Mac SDK.
   mac_sdk_min = "10.6"
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 63728d9..3972a5c 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -22,11 +22,18 @@
 }
 
 source_set("options_sources") {
-  visibility = [ ":deps" ]
+  visibility = [
+    ":deps",
+    "//:gn_visibility",
+  ]
   sources = [
     "//build/sanitizers/sanitizer_options.cc",
   ]
 
+  if (is_asan) {
+    sources += [ "//build/sanitizers/asan_suppressions.cc" ]
+  }
+
   if (is_tsan) {
     sources += [ "//build/sanitizers/tsan_suppressions.cc" ]
   }
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
index 057971d..e5a9c2b 100644
--- a/build/config/sysroot.gni
+++ b/build/config/sysroot.gni
@@ -5,6 +5,8 @@
 # This header file defines the "sysroot" variable which is the absolute path
 # of the sysroot. If no sysroot applies, the variable will be an empty string.
 
+import("//build/config/chrome_build.gni")
+
 declare_args() {
   # The absolute path of the sysroot that is applied when compiling using
   # the target toolchain.
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 58e7ff5..4257cc0 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -2,36 +2,40 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# This file defines three targets that we are using to
-# track the progress of the GYP->GN migration:
+# This file defines five targets that we are using to track the progress of the
+# GYP->GN migration:
 #
-# If you run 'ninja gn_build gyp_remaining gyp_groups', and then
-# run 'ninja', the second ninja invocation should do nothing. This
-# indicates that everything built by a ninja build is in fact
-# listed in one of these targets.
+# 'both_gn_and_gyp' lists what GN is currently capable of building and should
+# match the 'both_gn_and_gyp' target in //BUILD.gn.
 #
-# 'gn_all' lists what GN is currently capable of building and should
-#          match the 'gn_all' target in //BUILD.gn.
+# 'gyp_all' Should include everything built when building "all"; i.e., if you
+# type 'ninja gyp_all' and then 'ninja all', the second build should do
+# nothing. 'gyp_all' should just depend on the other four targets.
+#
+# 'gyp_only' lists any targets that are not meant to be ported over to the GN
+# build.
 #
 # 'gyp_remaining' lists all of the targets that still need to be converted,
-#          i.e., all of the other (non-empty) targets that a GYP build
-#          will build.
+# i.e., all of the other (non-empty) targets that a GYP build will build.
 #
-# 'gyp_groups' lists any empty (group) targets in the GYP build that
-#          are not picked up by gn_all or gyp_remaining; this is a
-#          separate target to ensure that when we build it, only
-#          stamp targets file are we don't accidentally pick up something
-#          not listed in one of the other two targets.
-#
-# TODO(GYP), TODO(dpranke) Add a build step to the bot that enforces the
-#          above contracts.
+# TODO(GYP): crbug.com/481694. Add a build step to the bot that enforces the
+# above contracts.
 
 {
   'targets': [
     {
-      # This target should mirror the structure of //:gn_all
-      # as closely as possible, for ease of comparison.
-      'target_name': 'gn_all',
+      'target_name': 'gyp_all',
+      'type': 'none',
+      'dependencies': [
+        'both_gn_and_gyp',
+        'gyp_only',
+        'gyp_remaining',
+      ]
+    },
+    {
+      # This target should mirror the structure of //:both_gn_and_gyp
+      # in src/BUILD.gn as closely as possible, for ease of comparison.
+      'target_name': 'both_gn_and_gyp',
       'type': 'none',
       'dependencies': [
         '../base/base.gyp:base_i18n_perftests',
@@ -98,6 +102,7 @@
         '../media/media.gyp:ffmpeg_regression_tests',  # TODO(GYP) this should be conditional on media_use_ffmpeg
         '../media/media.gyp:media_perftests',
         '../media/media.gyp:media_unittests',
+        '../media/midi/midi.gyp:midi_unittests',
         '../media/cast/cast.gyp:cast_benchmarks',
         '../media/cast/cast.gyp:cast_unittests',
         '../media/cast/cast.gyp:generate_barcode_video',
@@ -197,6 +202,7 @@
         '../ui/display/display.gyp:display_unittests',
         '../ui/events/events.gyp:events_unittests',
         '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+        '../ui/gl/gl_tests.gyp:gl_unittests',
         '../ui/message_center/message_center.gyp:message_center_unittests',
         '../ui/snapshot/snapshot.gyp:snapshot_unittests',
         '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
@@ -460,6 +466,7 @@
         ['OS=="win"', {
           'dependencies': [
             '../base/base.gyp:pe_image_test',
+            '../chrome/chrome.gyp:crash_service',
             '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
             '../chrome_elf/chrome_elf.gyp:dll_hash_main',
             '../components/components.gyp:wifi_test',
@@ -521,6 +528,7 @@
             '../gpu/gpu.gyp:gpu_unittests_run',
             '../media/cast/cast.gyp:cast_unittests_run',
             '../media/media.gyp:media_unittests_run',
+            '../media/midi/midi.gyp:midi_unittests_run',
             '../net/net.gyp:net_unittests_run',
             '../sql/sql.gyp:sql_unittests_run',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests_run',
@@ -606,7 +614,6 @@
             '../chrome/chrome.gyp:app_installer',
             '../chrome/chrome.gyp:app_installer_unittests',
             '../chrome/chrome.gyp:app_shim',
-            '../chrome/chrome.gyp:crash_service',
             '../chrome/chrome.gyp:gcapi_dll',
             '../chrome/chrome.gyp:gcapi_test',
             '../chrome/chrome.gyp:installer_util_unittests',
@@ -666,39 +673,6 @@
         }],
       ],
     },
-    {
-      # This target, when built, should cause no actual work
-      # to be done, just update a bunch of stamp files.
-      'target_name': 'gyp_groups',
-      'type': 'none',
-      'dependencies': [
-        'All',
-        'blink_tests',
-        'chromium_builder_asan',
-        'chromium_builder_chromedriver',
-        'chromium_builder_perf',
-        'chromium_builder_tests',
-        'chromium_builder_webrtc',
-        'chromium_gpu_builder',
-        'chromium_gpu_debug_builder',
-      ],
-      'conditions': [
-        ['use_aura==1', {
-          'dependencies': [
-            'aura_builder',
-          ]
-        }],
-        ['OS=="win"', {
-          'dependencies': [
-            'chromium_builder',
-            'chromium_builder_dbg_drmemory_win',
-            'chromium_builder_nacl_sdk',
-            'chromium_builder_lkgr_drmemory_win',
-            'chromium_builder_dbg_tsan_win',
-          ],
-        }],
-      ],
-    },
   ]
 }
 
diff --git a/build/gyp_chromium b/build/gyp_chromium
index 4ed15ba..736062e 100755
--- a/build/gyp_chromium
+++ b/build/gyp_chromium
@@ -254,16 +254,18 @@
     else:
       args.append(os.path.join(script_dir, 'all.gyp'))
 
+  supplemental_includes = GetSupplementalFiles()
+  gyp_vars_dict = GetGypVars(supplemental_includes)
   # There shouldn't be a circular dependency relationship between .gyp files,
   # but in Chromium's .gyp files, on non-Mac platforms, circular relationships
   # currently exist.  The check for circular dependencies is currently
-  # bypassed on other platforms, but is left enabled on the Mac, where a
-  # violation of the rule causes Xcode to misbehave badly.
+  # bypassed on other platforms, but is left enabled on iOS, where a violation
+  # of the rule causes Xcode to misbehave badly.
   # TODO(mark): Find and kill remaining circular dependencies, and remove this
   # option.  http://crbug.com/35878.
   # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the
   # list.
-  if sys.platform not in ('darwin',):
+  if gyp_vars_dict.get('OS') != 'ios':
     args.append('--no-circular-check')
 
   # We explicitly don't support the make gyp generator (crbug.com/348686). Be
@@ -285,9 +287,6 @@
   if syntax_check and int(syntax_check):
     args.append('--check')
 
-  supplemental_includes = GetSupplementalFiles()
-  gyp_vars_dict = GetGypVars(supplemental_includes)
-
   # TODO(dmikurube): Remove these checks and messages after a while.
   if ('linux_use_tcmalloc' in gyp_vars_dict or
       'android_use_tcmalloc' in gyp_vars_dict):
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index 6473794..2a2d50b 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -73,11 +73,11 @@
 fi
 
 lsb_release=$(lsb_release --codename --short)
-ubuntu_codenames="(precise|trusty|utopic)"
+ubuntu_codenames="(precise|trusty|utopic|vivid)"
 if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
   if [[ ! $lsb_release =~ $ubuntu_codenames ]]; then
-    echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty) and " \
-        "14.10 (utopic) are currently supported" >&2
+    echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty), " \
+      "14.10 (utopic) and 15.04 (vivid) are currently supported" >&2
     exit 1
   fi
 
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 18239b7..e25efbc 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -100,6 +100,7 @@
 IDR_TOOLBAR_SHADOW_FULL_BLEED
 IDR_TRANSLATE_JS
 IDR_UBER_UTILS_JS
+IDR_WEBUI_CSS_TEXT_DEFAULTS
 IDR_WEBUI_I18N_TEMPLATE_JS
 IDR_WEBUI_I18N_TEMPLATE_POLYMER_JS
 IDR_WEBUI_JSTEMPLATE_JS
diff --git a/build/isolate.gypi b/build/isolate.gypi
index 7b050e2..10033da 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -88,6 +88,7 @@
         # once support for user-defined config variables is added.
         '--config-variable',
           'internal_gles2_conform_tests=<(internal_gles2_conform_tests)',
+        '--config-variable', 'kasko=<(kasko)',
         '--config-variable', 'libpeer_target_type=<(libpeer_target_type)',
         '--config-variable', 'lsan=<(lsan)',
         '--config-variable', 'msan=<(msan)',
diff --git a/build/json_schema_api.gni b/build/json_schema_api.gni
index 68a9fdd..aa6365b 100644
--- a/build/json_schema_api.gni
+++ b/build/json_schema_api.gni
@@ -46,7 +46,10 @@
 #   If any deps are specified they will be inherited by the static library
 #   target.
 #
-# The static library target also inherits the visibility and output_name
+# generate_static_library [optional, defaults to false]
+#   Produces a static library instead of a source_set.
+#
+# The generated library target also inherits the visibility and output_name
 # of its invoker.
 
 template("json_schema_api") {
@@ -75,7 +78,6 @@
     visibility = target_visibility
   }
 
-  sources = invoker.sources
   root_namespace = invoker.root_namespace
 
   compiler_root = "//tools/json_schema_compiler"
@@ -97,6 +99,7 @@
     schema_generator_name = target_name + "_schema_generator"
     action_foreach(schema_generator_name) {
       script = compiler_script
+      sources = invoker.sources
       inputs = compiler_sources
       outputs = [
         "$target_gen_dir/{{source_name_part}}.cc",
@@ -127,7 +130,7 @@
     bundle_generator_schema_name = target_name + "_bundle_generator_schema"
     action(bundle_generator_schema_name) {
       script = compiler_script
-      inputs = compiler_sources + sources + uncompiled_sources
+      inputs = compiler_sources + invoker.sources + uncompiled_sources
       outputs = [
         "$target_gen_dir/generated_schemas.cc",
         "$target_gen_dir/generated_schemas.h",
@@ -138,7 +141,7 @@
                "--namespace=$root_namespace",
                "--generator=cpp-bundle-schema",
                "--include-rules=$schema_include_rules",
-             ] + rebase_path(sources, root_build_dir) +
+             ] + rebase_path(invoker.sources, root_build_dir) +
              rebase_path(uncompiled_sources, root_build_dir)
     }
   }
@@ -157,7 +160,7 @@
         target_name + "_bundle_generator_registration"
     action(bundle_generator_registration_name) {
       script = compiler_script
-      inputs = compiler_sources + sources + uncompiled_sources
+      inputs = compiler_sources + invoker.sources + uncompiled_sources
       outputs = [
         "$root_gen_dir/$impl_dir/generated_api_registration.cc",
         "$root_gen_dir/$impl_dir/generated_api_registration.h",
@@ -169,43 +172,69 @@
                "--generator=cpp-bundle-registration",
                "--impl-dir=" + rebase_path(impl_dir, "//"),
                "--include-rules=$schema_include_rules",
-             ] + rebase_path(sources, root_build_dir) +
+             ] + rebase_path(invoker.sources, root_build_dir) +
              rebase_path(uncompiled_sources, root_build_dir)
     }
   }
 
-  source_set(target_name) {
-    sources = []
-    deps = []
-    public_deps = []
+  # Compute the contents of the library/source set.
+  lib_sources = invoker.sources
+  lib_deps = []
+  lib_public_deps = []
+  lib_extra_configs = []
 
-    if (schemas) {
-      sources += get_target_outputs(":$schema_generator_name")
-      public_deps += [ ":$schema_generator_name" ]
-      deps += [ "//tools/json_schema_compiler:generated_api_util" ]
-      configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-    }
+  if (schemas) {
+    lib_sources += get_target_outputs(":$schema_generator_name")
+    lib_public_deps += [ ":$schema_generator_name" ]
+    lib_deps += [ "//tools/json_schema_compiler:generated_api_util" ]
+    lib_extra_configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+  }
 
-    if (bundle) {
-      sources += get_target_outputs(":$bundle_generator_schema_name")
-      deps += [ ":$bundle_generator_schema_name" ]
-    }
+  if (bundle) {
+    lib_sources += get_target_outputs(":$bundle_generator_schema_name")
+    lib_deps += [ ":$bundle_generator_schema_name" ]
+  }
 
-    if (bundle_registration) {
-      sources += get_target_outputs(":$bundle_generator_registration_name")
-      deps += [ ":$bundle_generator_registration_name" ]
-    }
+  if (bundle_registration) {
+    lib_sources += get_target_outputs(":$bundle_generator_registration_name")
+    lib_deps += [ ":$bundle_generator_registration_name" ]
+  }
 
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
-    public_configs = [ ":$generated_config_name" ]
+  if (defined(invoker.deps)) {
+    lib_deps += invoker.deps
+  }
 
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
+  # Generate either a static library or a source set.
+  if (defined(invoker.generate_static_library) &&
+      invoker.generate_static_library) {
+    static_library(target_name) {
+      sources = lib_sources
+      deps = lib_deps
+      public_deps = lib_public_deps
+      configs += lib_extra_configs
+      public_configs = [ ":$generated_config_name" ]
+
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
     }
-    if (defined(invoker.output_name)) {
-      output_name = invoker.output_name
+  } else {
+    source_set(target_name) {
+      sources = lib_sources
+      deps = lib_deps
+      public_deps = lib_public_deps
+      configs += lib_extra_configs
+      public_configs = [ ":$generated_config_name" ]
+
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
     }
   }
 }
diff --git a/build/sanitizers/lsan_suppressions.cc b/build/sanitizers/lsan_suppressions.cc
index a076ba0..f9aae3e 100644
--- a/build/sanitizers/lsan_suppressions.cc
+++ b/build/sanitizers/lsan_suppressions.cc
@@ -66,6 +66,9 @@
 "leak:gin/object_template_builder.h\n"
 "leak:gin::internal::Dispatcher\n"
 "leak:blink::LocalDOMWindow::getComputedStyle\n"
+// This should really be RemoteDOMWindow::create, but symbolization is
+// weird in release builds. https://crbug.com/484760
+"leak:blink::RemoteFrame::create\n"
 
 // http://crbug.com/356785
 "leak:content::RenderViewImplTest_DecideNavigationPolicyForWebUI_Test::TestBody\n"
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 352b41f..e053a16 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -157,6 +157,9 @@
 "race:PrepareTextureMailbox\n"
 "race:cc::LayerTreeHost::PaintLayerContents\n"
 
+// http://crbug.com/476529
+"deadlock:cc::VideoLayerImpl::WillDraw\n"
+
 // http://crbug.com/328826
 "race:gLCDOrder\n"
 "race:gLCDOrientation\n"
@@ -295,9 +298,6 @@
 // https://crbug.com/430533
 "race:TileTaskGraphRunner::Run\n"
 
-// https://crbug.com/437044
-"race:SkEventTracer\n"
-
 // https://crbug.com/448203
 "race:blink::RemoteFrame::detach\n"
 
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni
index 09a04c1..35bbed3 100644
--- a/build/secondary/tools/grit/grit_rule.gni
+++ b/build/secondary/tools/grit/grit_rule.gni
@@ -75,6 +75,7 @@
 #     # You can also put deps here if the grit source depends on generated
 #     # files.
 #   }
+import("//build/config/chrome_build.gni")
 import("//build/config/crypto.gni")
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 16034ea..df2b73a 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -157,7 +157,7 @@
         RenderPassTextureSize(render_passes_in_draw_order[i])));
 
   std::vector<RenderPassId> passes_to_delete;
-  base::ScopedPtrHashMap<RenderPassId, ScopedResource>::const_iterator
+  base::ScopedPtrHashMap<RenderPassId, scoped_ptr<ScopedResource>>::const_iterator
       pass_iter;
   for (pass_iter = render_pass_textures_.begin();
        pass_iter != render_pass_textures_.end();
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index e119d28..3a8d175 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -138,7 +138,7 @@
       DrawingFrame* frame,
       scoped_ptr<CopyOutputRequest> request) = 0;
 
-  base::ScopedPtrHashMap<RenderPassId, ScopedResource> render_pass_textures_;
+  base::ScopedPtrHashMap<RenderPassId, scoped_ptr<ScopedResource>> render_pass_textures_;
   OutputSurface* output_surface_;
   ResourceProvider* resource_provider_;
   scoped_ptr<OverlayProcessor> overlay_processor_;
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 8ae3b04..1c4f431 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -86,7 +86,7 @@
   ResourceProvider* provider_;
 
   class RenderPassIdAllocator;
-  typedef base::ScopedPtrHashMap<SurfaceId, RenderPassIdAllocator>
+  typedef base::ScopedPtrHashMap<SurfaceId, scoped_ptr<RenderPassIdAllocator>>
       RenderPassIdAllocatorMap;
   RenderPassIdAllocatorMap render_pass_allocator_map_;
   int next_render_pass_id_;
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index b6b627f..afc0b81 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -68,8 +68,8 @@
   SurfaceFactoryClient* client_;
   SurfaceResourceHolder holder_;
 
-  typedef base::ScopedPtrHashMap<SurfaceId, Surface> OwningSurfaceMap;
-  base::ScopedPtrHashMap<SurfaceId, Surface> surface_map_;
+  typedef base::ScopedPtrHashMap<SurfaceId, scoped_ptr<Surface>> OwningSurfaceMap;
+  OwningSurfaceMap surface_map_;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceFactory);
 };
diff --git a/mojo/common/task_tracker.cc b/mojo/common/task_tracker.cc
index c0ffd3f..8665799 100644
--- a/mojo/common/task_tracker.cc
+++ b/mojo/common/task_tracker.cc
@@ -54,7 +54,6 @@
   if (!birth_)
     return false;
 
-  tracked_objects::ThreadData::PrepareForStartOfRun(birth_);
   (new (stopwatch()) tracked_objects::TaskStopwatch())->Start();
   return true;
 }
diff --git a/mojo/common/task_tracker_unittest.cc b/mojo/common/task_tracker_unittest.cc
index 77f7da8..090e586 100644
--- a/mojo/common/task_tracker_unittest.cc
+++ b/mojo/common/task_tracker_unittest.cc
@@ -15,7 +15,7 @@
  public:
   void SetUp() override {
     tracked_objects::ThreadData::InitializeAndSetTrackingStatus(
-        tracked_objects::ThreadData::PROFILING_CHILDREN_ACTIVE);
+        tracked_objects::ThreadData::PROFILING_ACTIVE);
   }
 
   void TearDown() override {
@@ -31,10 +31,10 @@
   TaskTracker::EndTracking(id0);
 
   tracked_objects::ProcessDataSnapshot snapshot;
-  tracked_objects::ThreadData::Snapshot(&snapshot);
+  tracked_objects::ThreadData::Snapshot(0, &snapshot);
 
   // Nested one is ignored.
-  EXPECT_EQ(1U, snapshot.phased_process_data_snapshots[0].tasks.size());
+  EXPECT_EQ(1U, snapshot.phased_snapshots[0].tasks.size());
 }
 
 TEST_F(TaskTrackerTest, Twice) {
@@ -44,9 +44,9 @@
   TaskTracker::EndTracking(id1);
 
   tracked_objects::ProcessDataSnapshot snapshot;
-  tracked_objects::ThreadData::Snapshot(&snapshot);
+  tracked_objects::ThreadData::Snapshot(0, &snapshot);
 
-  EXPECT_EQ(2U, snapshot.phased_process_data_snapshots[0].tasks.size());
+  EXPECT_EQ(2U, snapshot.phased_snapshots[0].tasks.size());
 }
 
 }  // namespace test
diff --git a/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc b/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc
index 95a7b5c..461b475 100644
--- a/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc
+++ b/mojo/services/view_manager/public/cpp/tests/run_all_unittests.cc
@@ -10,5 +10,5 @@
   mojo::ViewManagerTestSuite test_suite(argc, argv);
 
   return base::LaunchUnitTests(
-      argc, argv, base::Bind(&TestSuite::Run, base::Unretained(&test_suite)));
+      argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
 }
diff --git a/mojo/tests/task_tracker_perftest.cc b/mojo/tests/task_tracker_perftest.cc
index d728120..8183777 100644
--- a/mojo/tests/task_tracker_perftest.cc
+++ b/mojo/tests/task_tracker_perftest.cc
@@ -66,7 +66,7 @@
 
   void SetUp() override {
     tracked_objects::ThreadData::InitializeAndSetTrackingStatus(
-        tracked_objects::ThreadData::PROFILING_CHILDREN_ACTIVE);
+        tracked_objects::ThreadData::PROFILING_ACTIVE);
   }
 
   void TearDown() override {
diff --git a/sandbox/linux/bpf_dsl/codegen.cc b/sandbox/linux/bpf_dsl/codegen.cc
index 99b78ed..bc2c7a2 100644
--- a/sandbox/linux/bpf_dsl/codegen.cc
+++ b/sandbox/linux/bpf_dsl/codegen.cc
@@ -131,7 +131,8 @@
   CHECK_EQ(program_.size(), equivalent_.size());
 
   Node res = program_.size();
-  program_.push_back(sock_filter{code, jt, jf, k});
+  program_.push_back(sock_filter{
+      code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k});
   equivalent_.push_back(res);
   return res;
 }
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
index d4d5280..f38232f 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -22,6 +22,7 @@
 #include "sandbox/linux/seccomp-bpf/errorcode.h"
 #include "sandbox/linux/system_headers/linux_filter.h"
 #include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
 
 namespace sandbox {
 namespace bpf_dsl {
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
index 7f4866d..ca28c1d 100644
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -11,7 +11,9 @@
 // All x86_64 builds use a new enough bionic to have sys/user.h.
 #if !defined(__BIONIC__) || defined(__x86_64__)
 #include <sys/types.h>  // Fix for gcc 4.7, make sure __uint16_t is defined.
+#if !defined(__native_client_nonsfi__)
 #include <sys/user.h>
+#endif
 #if defined(__mips__)
 // sys/user.h in eglibc misses size_t definition
 #include <stddef.h>
@@ -50,10 +52,10 @@
                                  8*(nr) + 0)
 
 
-#if defined(__BIONIC__)
-// Old Bionic versions don't have sys/user.h, so we just define regs_struct
-// directly.  This can be removed once we no longer need to support these old
-// Bionic versions.
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly.  This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
 struct regs_struct {
   long int ebx;
   long int ecx;
@@ -149,10 +151,10 @@
 #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
                                  8*(nr) + 0)
 
-#if defined(__BIONIC__)
-// Old Bionic versions don't have sys/user.h, so we just define regs_struct
-// directly.  This can be removed once we no longer need to support these old
-// Bionic versions.
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly.  This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
 struct regs_struct {
   unsigned long uregs[18];
 };
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index d449156..05250d1 100644
--- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -188,12 +188,9 @@
    static const char kSeccompKillError[] =
       __FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n";
   WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1);
-  // Make "request" volatile so that we can see it on the stack in a minidump.
-  volatile uint64_t pid = args.args[0];
-  volatile char* addr = reinterpret_cast<volatile char*>(pid & 0xFFF);
-  *addr = '\0';
-  // Hit the NULL page if this fails.
-  addr = reinterpret_cast<volatile char*>(pid & 0xFFF);
+  // Make "pid" volatile so that we can see it on the stack in a minidump.
+  volatile uint64_t my_pid = sys_getpid();
+  volatile char* addr = reinterpret_cast<volatile char*>(my_pid & 0xFFF);
   *addr = '\0';
   for (;;)
     _exit(1);
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 282e727..60c16d3 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -11,7 +11,6 @@
 #include <sched.h>
 #include <signal.h>
 #include <stdint.h>
-#include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
@@ -32,6 +31,11 @@
 #include "sandbox/linux/system_headers/linux_futex.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
 
+// PNaCl toolchain does not provide sys/ioctl.h header.
+#if !defined(OS_NACL_NONSFI)
+#include <sys/ioctl.h>
+#endif
+
 #if defined(OS_ANDROID)
 
 #if !defined(F_DUPFD_CLOEXEC)
@@ -104,6 +108,7 @@
 
 namespace sandbox {
 
+#if !defined(OS_NACL_NONSFI)
 // Allow Glibc's and Android pthread creation flags, crash on any other
 // thread creation attempts and EPERM attempts to use neither
 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
@@ -261,21 +266,6 @@
       .Else(CrashSIGSYS());
 }
 
-ResultExpr RestrictClockID() {
-  static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
-  const Arg<clockid_t> clockid(0);
-  return If(
-#if defined(OS_CHROMEOS)
-             // Allow the special clock for Chrome OS used by Chrome tracing.
-             clockid == base::TimeTicks::kClockSystemTrace ||
-#endif
-                 clockid == CLOCK_MONOTONIC ||
-                 clockid == CLOCK_PROCESS_CPUTIME_ID ||
-                 clockid == CLOCK_REALTIME ||
-                 clockid == CLOCK_THREAD_CPUTIME_ID,
-             Allow()).Else(CrashSIGSYS());
-}
-
 ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
   switch (sysno) {
     case __NR_sched_getaffinity:
@@ -306,5 +296,21 @@
   const Arg<int> who(0);
   return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS());
 }
+#endif  // !defined(OS_NACL_NONSFI)
+
+ResultExpr RestrictClockID() {
+  static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
+  const Arg<clockid_t> clockid(0);
+  return If(
+#if defined(OS_CHROMEOS)
+             // Allow the special clock for Chrome OS used by Chrome tracing.
+             clockid == base::TimeTicks::kClockSystemTrace ||
+#endif
+                 clockid == CLOCK_MONOTONIC ||
+                 clockid == CLOCK_PROCESS_CPUTIME_ID ||
+                 clockid == CLOCK_REALTIME ||
+                 clockid == CLOCK_THREAD_CPUTIME_ID,
+             Allow()).Else(CrashSIGSYS());
+}
 
 }  // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index d557c5f..0ec396d 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -67,15 +67,6 @@
 // |target_pid| while calling setpriority(2) / getpriority(2).
 SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid);
 
-// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime().
-// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
-// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID.  In particular, this disallows
-// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
-// returned by {clock,pthread}_getcpuclockid), which can leak information
-// about the state of the host OS.
-// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
-SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();
-
 // Restricts |pid| for sched_* syscalls which take a pid as the first argument.
 // We only allow calling these syscalls if the pid argument is equal to the pid
 // of the sandboxed process or 0 (indicating the current thread).  The following
@@ -95,6 +86,15 @@
 // process).
 SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetrusage();
 
+// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime().
+// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID.  In particular, this disallows
+// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
+// returned by {clock,pthread}_getcpuclockid), which can leak information
+// about the state of the host OS.
+// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();
+
 }  // namespace sandbox.
 
 #endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
index 3b3c8db..bc6461f 100644
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -133,16 +133,21 @@
 #else
     ".arm\n"
 #endif
-    "SyscallAsm:.fnstart\n"
+    "SyscallAsm:\n"
+#if !defined(__native_client_nonsfi__)
+    // .fnstart and .fnend pseudo operations creates unwind table.
+    // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
+    // is not provided by PNaCl toolchain. Disable it.
+    ".fnstart\n"
+#endif
     "@ args = 0, pretend = 0, frame = 8\n"
     "@ frame_needed = 1, uses_anonymous_args = 0\n"
 #if defined(__thumb__)
     ".cfi_startproc\n"
     "push {r7, lr}\n"
+    ".save {r7, lr}\n"
     ".cfi_offset 14, -4\n"
     ".cfi_offset  7, -8\n"
-    "mov r7, sp\n"
-    ".cfi_def_cfa_register 7\n"
     ".cfi_def_cfa_offset 8\n"
 #else
     "stmfd sp!, {fp, lr}\n"
@@ -177,7 +182,11 @@
 #else
     "2:ldmfd sp!, {fp, pc}\n"
 #endif
+#if !defined(__native_client_nonsfi__)
+    // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
+    // for more details.
     ".fnend\n"
+#endif
     "9:.size SyscallAsm, 9b-SyscallAsm\n"
 #elif defined(__mips__)
     ".text\n"
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
index 79b7569..8f559e5 100644
--- a/sandbox/linux/seccomp-bpf/trap.cc
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -12,6 +12,7 @@
 #include <algorithm>
 #include <limits>
 
+#include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
@@ -121,15 +122,26 @@
 }
 
 void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) {
+  if (info) {
+    MSAN_UNPOISON(info, sizeof(*info));
+  }
+
+  // Obtain the signal context. This, most notably, gives us access to
+  // all CPU registers at the time of the signal.
+  ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+  if (ctx) {
+    MSAN_UNPOISON(ctx, sizeof(*ctx));
+  }
+
   if (!global_trap_) {
     RAW_SANDBOX_DIE(
         "This can't happen. Found no global singleton instance "
         "for Trap() handling.");
   }
-  global_trap_->SigSys(nr, info, void_context);
+  global_trap_->SigSys(nr, info, ctx);
 }
 
-void Trap::SigSys(int nr, LinuxSigInfo* info, void* void_context) {
+void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) {
   // Signal handlers should always preserve "errno". Otherwise, we could
   // trigger really subtle bugs.
   const int old_errno = errno;
@@ -137,7 +149,7 @@
   // Various sanity checks to make sure we actually received a signal
   // triggered by a BPF filter. If something else triggered SIGSYS
   // (e.g. kill()), there is really nothing we can do with this signal.
-  if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !void_context ||
+  if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx ||
       info->si_errno <= 0 ||
       static_cast<size_t>(info->si_errno) > trap_array_size_) {
     // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
@@ -148,9 +160,6 @@
     return;
   }
 
-  // Obtain the signal context. This, most notably, gives us access to
-  // all CPU registers at the time of the signal.
-  ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
 
   // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
   // most versions of glibc don't include this information in siginfo_t. So,
diff --git a/sandbox/linux/seccomp-bpf/trap.h b/sandbox/linux/seccomp-bpf/trap.h
index bbddeb7..50ac3fd 100644
--- a/sandbox/linux/seccomp-bpf/trap.h
+++ b/sandbox/linux/seccomp-bpf/trap.h
@@ -61,7 +61,7 @@
 
   // Make sure that SigSys is not inlined in order to get slightly better crash
   // dumps.
-  void SigSys(int nr, LinuxSigInfo* info, void* void_context)
+  void SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx)
       __attribute__((noinline));
   // We have a global singleton that handles all of our SIGSYS traps. This
   // variable must never be deallocated after it has been set up initially, as
diff --git a/sandbox/linux/seccomp-bpf/trap_unittest.cc b/sandbox/linux/seccomp-bpf/trap_unittest.cc
index 3d95e34..99f94bf 100644
--- a/sandbox/linux/seccomp-bpf/trap_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/trap_unittest.cc
@@ -12,7 +12,6 @@
 namespace sandbox {
 namespace {
 
-#if !defined(THREAD_SANITIZER)
 SANDBOX_TEST_ALLOW_NOISE(Trap, SigSysAction) {
   // This creates a global Trap instance, and registers the signal handler
   // (Trap::SigSysAction).
@@ -24,7 +23,6 @@
   // "Unexpected SIGSYS received." so it is necessary to allow the noise.
   raise(SIGSYS);
 }
-#endif
 
 }  // namespace
 }  // namespace sandbox
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
index fdfcb94..264eb68 100644
--- a/sandbox/linux/services/syscall_wrappers.cc
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -148,24 +148,38 @@
                  sizeof(linux_value));
 }
 
-#if defined(MEMORY_SANITIZER) || \
-    (defined(ARCH_CPU_X86_64) && defined(__GNUC__) && !defined(__clang__))
-// If MEMORY_SANITIZER is enabled, it is necessary to call sigaction() here,
-// rather than the direct syscall (sys_sigaction() defined by ourselves).
-// It is because, if MEMORY_SANITIZER is enabled, sigaction is wrapped, and
-// |act->sa_handler| is injected in order to unpoisonize the memory passed via
-// callback's arguments. Please see msan_interceptors.cc for more details.
-// So, if the direct syscall is used, as MEMORY_SANITIZER does not know about
-// it, sigaction() invocation in other places would be broken (in more precise,
-// returned |oldact| would have a broken |sa_handler| callback).
+#if (defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) ||  \
+     (defined(ARCH_CPU_X86_64) && !defined(__clang__))) && \
+    !defined(OS_NACL_NONSFI)
+// If MEMORY_SANITIZER or THREAD_SANITIZER is enabled, it is necessary to call
+// sigaction() here, rather than the direct syscall (sys_sigaction() defined
+// by ourselves).
+// It is because, if MEMORY_SANITIZER or THREAD_SANITIZER is enabled, sigaction
+// is wrapped, and |act->sa_handler| is injected in order to unpoisonize the
+// memory passed via callback's arguments for MEMORY_SANITIZER, or handle
+// signals to check thread consistency for THREAD_SANITIZER. Please see
+// msan_interceptors.cc and tsan_interceptors.cc for more details.
+// So, specifically, if MEMORY_SANITIZER is enabled while the direct syscall is
+// used, as MEMORY_SANITIZER does not know about it, sigaction() invocation in
+// other places would be broken (in more precise, returned |oldact| would have
+// a broken |sa_handler| callback).
 // Practically, it would break NaCl's signal handler installation.
 // cf) native_client/src/trusted/service_runtime/linux/nacl_signal.c.
+// As for THREAD_SANITIZER, the intercepted signal handlers are processed more
+// in other libc functions' interceptors (such as for raise()), so that it
+// would not work properly.
 //
 // Also on x86_64 architecture, we need naked function for rt_sigreturn.
 // However, there is no simple way to define it with GCC. Note that the body
 // of function is actually very small (only two instructions), but we need to
 // define much debug information in addition, otherwise backtrace() used by
 // base::StackTrace would not work so that some tests would fail.
+//
+// When this is built with PNaCl toolchain, we should always use sys_sigaction
+// below, because sigaction() provided by the toolchain is incompatible with
+// Linux's ABI. So, otherwise, it would just fail. Note that it is not
+// necessary to think about sigaction() invocation in other places even with
+// MEMORY_SANITIZER or THREAD_SANITIZER, because it would just fail there.
 int sys_sigaction(int signum,
                   const struct sigaction* act,
                   struct sigaction* oldact) {
diff --git a/sandbox/linux/services/yama.cc b/sandbox/linux/services/yama.cc
index 6658160..151f4bd 100644
--- a/sandbox/linux/services/yama.cc
+++ b/sandbox/linux/services/yama.cc
@@ -10,7 +10,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "base/basictypes.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
diff --git a/sandbox/linux/system_headers/linux_futex.h b/sandbox/linux/system_headers/linux_futex.h
index 91733a8..4e28403 100644
--- a/sandbox/linux/system_headers/linux_futex.h
+++ b/sandbox/linux/system_headers/linux_futex.h
@@ -5,7 +5,9 @@
 #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
 #define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
 
+#if !defined(__native_client_nonsfi__)
 #include <linux/futex.h>
+#endif  // !defined(__native_client_nonsfi__)
 
 #if !defined(FUTEX_WAIT)
 #define FUTEX_WAIT 0
diff --git a/services/view_manager/animation_runner.h b/services/view_manager/animation_runner.h
index 64bf494..b79c680 100644
--- a/services/view_manager/animation_runner.h
+++ b/services/view_manager/animation_runner.h
@@ -86,7 +86,7 @@
   };
 
   using ViewToAnimationMap =
-      base::ScopedPtrHashMap<ServerView*, ScheduledAnimationGroup>;
+      base::ScopedPtrHashMap<ServerView*, scoped_ptr<ScheduledAnimationGroup>>;
   using IdToViewsMap = std::map<AnimationId, std::set<ServerView*>>;
 
   void CancelAnimationForViewImpl(ServerView* view, CancelSource source);
diff --git a/services/window_manager/run_all_unittests.cc b/services/window_manager/run_all_unittests.cc
index 51fd967..f8f67b6 100644
--- a/services/window_manager/run_all_unittests.cc
+++ b/services/window_manager/run_all_unittests.cc
@@ -39,5 +39,5 @@
   window_manager::WindowManagerTestSuite test_suite(argc, argv);
 
   return base::LaunchUnitTests(
-      argc, argv, base::Bind(&TestSuite::Run, base::Unretained(&test_suite)));
+      argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
 }
diff --git a/sky/engine/web/tests/RunAllTests.cpp b/sky/engine/web/tests/RunAllTests.cpp
index 21048e9..0378d47 100644
--- a/sky/engine/web/tests/RunAllTests.cpp
+++ b/sky/engine/web/tests/RunAllTests.cpp
@@ -41,14 +41,14 @@
 #include "sky/engine/public/web/Sky.h"
 #include "sky/engine/testing/platform/platform_impl.h"
 
-int runHelper(TestSuite* testSuite) {
+int runHelper(base::TestSuite* testSuite) {
   base::MessageLoopForUI message_loop;
   blink::initialize(new sky::PlatformImpl());
   return testSuite->Run();
 }
 
 int main(int argc, char** argv) {
-  TestSuite test_suite(argc, argv);
+    base::TestSuite test_suite(argc, argv);
   return base::LaunchUnitTests(
       argc, argv, Bind(&runHelper, Unretained(&test_suite)));
 }
diff --git a/testing/android/appurify_support.gyp b/testing/android/appurify_support.gyp
new file mode 100644
index 0000000..2904368
--- /dev/null
+++ b/testing/android/appurify_support.gyp
@@ -0,0 +1,22 @@
+# 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.
+
+{
+  'conditions': [
+    ['OS=="android"', {
+      'targets': [
+        {
+          'target_name': 'appurify_support_java',
+          'type': 'none',
+          'variables': {
+            'java_in_dir': '../../testing/android/appurify_support/java',
+          },
+          'includes': [
+            '../../build/java.gypi',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/testing/android/appurify_support/BUILD.gn b/testing/android/appurify_support/BUILD.gn
new file mode 100644
index 0000000..871f9d0
--- /dev/null
+++ b/testing/android/appurify_support/BUILD.gn
@@ -0,0 +1,15 @@
+# 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("//build/config/android/rules.gni")
+
+# GYP: //testing/android/appurify_support.gyp:appurify_support_java
+android_library("appurify_support_java") {
+  chromium_code = true
+
+  java_files = [
+    "java/src/org/chromium/test/support/ResultsBundleGenerator.java",
+    "java/src/org/chromium/test/support/RobotiumBundleGenerator.java",
+  ]
+}
diff --git a/testing/android/appurify_support/java/src/org/chromium/test/support/ResultsBundleGenerator.java b/testing/android/appurify_support/java/src/org/chromium/test/support/ResultsBundleGenerator.java
new file mode 100644
index 0000000..c9588d9
--- /dev/null
+++ b/testing/android/appurify_support/java/src/org/chromium/test/support/ResultsBundleGenerator.java
@@ -0,0 +1,30 @@
+// 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.test.support;
+
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Creates a results Bundle.
+ */
+public interface ResultsBundleGenerator {
+
+    /** Indicates the state of a test.
+     */
+    static enum TestResult {
+        PASSED, FAILED, ERROR, UNKNOWN
+    }
+
+    /** Creates a bundle of test results from the provided raw results.
+
+        Note: actual bundle content and format may vary.
+
+        @param rawResults A map between test names and test results.
+     */
+    Bundle generate(Map<String, TestResult> rawResults);
+}
+
diff --git a/testing/android/appurify_support/java/src/org/chromium/test/support/RobotiumBundleGenerator.java b/testing/android/appurify_support/java/src/org/chromium/test/support/RobotiumBundleGenerator.java
new file mode 100644
index 0000000..167e7b9
--- /dev/null
+++ b/testing/android/appurify_support/java/src/org/chromium/test/support/RobotiumBundleGenerator.java
@@ -0,0 +1,56 @@
+// 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.test.support;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Map;
+
+/**
+ * Creates a results bundle that emulates the one created by Robotium.
+ */
+public class RobotiumBundleGenerator implements ResultsBundleGenerator {
+
+    private static final String TAG = "RobotiumBundleGenerator";
+
+    public Bundle generate(Map<String, ResultsBundleGenerator.TestResult> rawResults) {
+        int testsPassed = 0;
+        int testsFailed = 0;
+
+        for (Map.Entry<String, ResultsBundleGenerator.TestResult> entry : rawResults.entrySet()) {
+            switch (entry.getValue()) {
+                case PASSED:
+                    ++testsPassed;
+                    break;
+                case FAILED:
+                    // TODO(jbudorick): Remove this log message once AMP execution and
+                    // results handling has been stabilized.
+                    Log.d(TAG, "FAILED: " + entry.getKey());
+                    ++testsFailed;
+                    break;
+                default:
+                    Log.w(TAG, "Unhandled: " + entry.getKey() + ", "
+                            + entry.getValue().toString());
+                    break;
+            }
+        }
+
+        StringBuilder resultBuilder = new StringBuilder();
+        if (testsFailed > 0) {
+            resultBuilder.append(
+                    "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size())
+                    + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0");
+        } else {
+            resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)");
+        }
+
+        Bundle resultsBundle = new Bundle();
+        resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                resultBuilder.toString());
+        return resultsBundle;
+    }
+}
diff --git a/testing/android/broker/BUILD.gn b/testing/android/broker/BUILD.gn
new file mode 100644
index 0000000..8daa040
--- /dev/null
+++ b/testing/android/broker/BUILD.gn
@@ -0,0 +1,13 @@
+# 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("//build/config/android/rules.gni")
+
+# GYP: //testing/android/on_device_instrumentation.gyp:broker_java
+android_library("broker_java") {
+  chromium_code = true
+
+  java_files =
+      [ "java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java" ]
+}
diff --git a/testing/android/broker/java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java b/testing/android/broker/java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java
new file mode 100644
index 0000000..cd755d0
--- /dev/null
+++ b/testing/android/broker/java/src/org/chromium/test/broker/OnDeviceInstrumentationBroker.java
@@ -0,0 +1,64 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.test.broker;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * An Activity target for OnDeviceInstrumentationDriver that starts the specified
+ * Instrumentation test.
+ */
+public class OnDeviceInstrumentationBroker extends Activity {
+
+    public static final String EXTRA_INSTRUMENTATION_PACKAGE =
+            "org.chromium.test.broker.OnDeviceInstrumentationBroker."
+                    + "InstrumentationPackage";
+    public static final String EXTRA_INSTRUMENTATION_CLASS =
+            "org.chromium.test.broker.OnDeviceInstrumentationBroker."
+                    + "InstrumentationClass";
+    public static final String EXTRA_TARGET_ARGS =
+            "org.chromium.test.broker.OnDeviceInstrumentationBroker.TargetArgs";
+    public static final String EXTRA_TEST =
+            "org.chromium.test.broker.OnDeviceInstrumentationBroker.Test";
+
+    private static final String TAG = "OnDeviceInstrumentationBroker";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.d(TAG, "onCreate()");
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        Intent i = getIntent();
+        String instrumentationPackage = i.getStringExtra(EXTRA_INSTRUMENTATION_PACKAGE);
+        String instrumentationClass = i.getStringExtra(EXTRA_INSTRUMENTATION_CLASS);
+        Bundle targetArgs = i.getBundleExtra(EXTRA_TARGET_ARGS);
+        String test = i.getStringExtra(EXTRA_TEST);
+
+        if (instrumentationPackage == null || instrumentationClass == null) {
+            finish();
+            return;
+        }
+
+        ComponentName instrumentationComponent =
+                new ComponentName(instrumentationPackage, instrumentationClass);
+
+        if (test != null) {
+            targetArgs.putString("class", test);
+        }
+
+        startInstrumentation(instrumentationComponent, null, targetArgs);
+        finish();
+    }
+}
+
diff --git a/testing/android/driver/BUILD.gn b/testing/android/driver/BUILD.gn
new file mode 100644
index 0000000..436ac63
--- /dev/null
+++ b/testing/android/driver/BUILD.gn
@@ -0,0 +1,21 @@
+# 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("//build/config/android/rules.gni")
+
+# GYP: //testing/android/on_device_instrumentation.gyp:driver_apk
+android_apk("driver_apk") {
+  android_manifest = "java/AndroidManifest.xml"
+  apk_name = "OnDeviceInstrumentationDriver"
+  testonly = true
+
+  deps = [
+    "//testing/android/appurify_support:appurify_support_java",
+    "//testing/android/broker:broker_java",
+    "//testing/android/reporter:reporter_java",
+  ]
+
+  java_files =
+      [ "java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java" ]
+}
diff --git a/testing/android/driver/java/AndroidManifest.xml b/testing/android/driver/java/AndroidManifest.xml
new file mode 100644
index 0000000..c7e99ef
--- /dev/null
+++ b/testing/android/driver/java/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.chromium.test.driver"
+      android:versionCode="1"
+      android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+
+    <application android:label="OnDeviceInstrumentationDriver" />
+
+    <instrumentation android:name="org.chromium.test.driver.OnDeviceInstrumentationDriver"
+            android:targetPackage="org.chromium.test.driver"
+            android:label="OnDeviceInstrumentationDriver"/>
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+</manifest>
diff --git a/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java b/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
new file mode 100644
index 0000000..78c571a
--- /dev/null
+++ b/testing/android/driver/java/src/org/chromium/test/driver/OnDeviceInstrumentationDriver.java
@@ -0,0 +1,271 @@
+// 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.test.driver;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import org.chromium.test.broker.OnDeviceInstrumentationBroker;
+import org.chromium.test.reporter.TestStatusReceiver;
+import org.chromium.test.reporter.TestStatusReporter;
+import org.chromium.test.support.ResultsBundleGenerator;
+import org.chromium.test.support.RobotiumBundleGenerator;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * An Instrumentation that drives instrumentation tests from outside the app.
+ */
+public class OnDeviceInstrumentationDriver extends Instrumentation {
+
+    private static final String TAG = "OnDeviceInstrumentationDriver";
+
+    private static final String EXTRA_TEST_LIST =
+            "org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList";
+    private static final String EXTRA_TEST_LIST_FILE =
+            "org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile";
+    private static final String EXTRA_TARGET_PACKAGE =
+            "org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage";
+    private static final String EXTRA_TARGET_CLASS =
+            "org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass";
+
+    private static final Pattern COMMA = Pattern.compile(",");
+    private static final int TEST_WAIT_TIMEOUT = 5 * TestStatusReporter.HEARTBEAT_INTERVAL_MS;
+
+    private boolean mDriverStarted;
+    private Thread mDriverThread;
+    private Bundle mTargetArgs;
+    private String mTargetClass;
+    private String mTargetPackage;
+    private List<String> mTestClasses;
+
+    /** Parse any arguments and prepare to run tests.
+
+        @param arguments The arguments to parse.
+     */
+    @Override
+    public void onCreate(Bundle arguments) {
+        mTargetArgs = new Bundle(arguments);
+        mTargetPackage = arguments.getString(EXTRA_TARGET_PACKAGE);
+        if (mTargetPackage == null) {
+            fail("No target package.");
+            return;
+        }
+        mTargetArgs.remove(EXTRA_TARGET_PACKAGE);
+
+        mTargetClass = arguments.getString(EXTRA_TARGET_CLASS);
+        if (mTargetClass == null) {
+            fail("No target class.");
+            return;
+        }
+        mTargetArgs.remove(EXTRA_TARGET_CLASS);
+
+        mTestClasses = new ArrayList<String>();
+        String testList = arguments.getString(EXTRA_TEST_LIST);
+        if (testList != null) {
+            mTestClasses.addAll(Arrays.asList(COMMA.split(testList)));
+            mTargetArgs.remove(EXTRA_TEST_LIST);
+        }
+
+        String testListFilePath = arguments.getString(EXTRA_TEST_LIST_FILE);
+        if (testListFilePath != null) {
+            File testListFile = new File(Environment.getExternalStorageDirectory(),
+                    testListFilePath);
+            try {
+                BufferedReader testListFileReader =
+                        new BufferedReader(new FileReader(testListFile));
+                String test;
+                while ((test = testListFileReader.readLine()) != null) {
+                    mTestClasses.add(test);
+                }
+                testListFileReader.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Error reading " + testListFile.getAbsolutePath(), e);
+            }
+            mTargetArgs.remove(EXTRA_TEST_LIST_FILE);
+        }
+
+        if (mTestClasses.isEmpty()) {
+            fail("No tests.");
+            return;
+        }
+
+        mDriverThread = new Thread(
+                new Driver(mTargetPackage, mTargetClass, mTargetArgs, mTestClasses));
+
+        start();
+    }
+
+    /** Start running tests. */
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        // Start the driver on its own thread s.t. it can block while the main thread's
+        // Looper receives and handles messages.
+        if (!mDriverStarted) {
+            mDriverThread.start();
+            mDriverStarted = true;
+        }
+    }
+
+    /** Clean up the reporting service. */
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    private class Driver implements Runnable {
+
+        private static final String TAG = OnDeviceInstrumentationDriver.TAG + ".Driver";
+
+        private Bundle mTargetArgs;
+        private String mTargetClass;
+        private String mTargetPackage;
+        private List<String> mTestClasses;
+
+        public Driver(String targetPackage, String targetClass, Bundle targetArgs,
+                List<String> testClasses) {
+            mTargetPackage = targetPackage;
+            mTargetClass = targetClass;
+            mTargetArgs = targetArgs;
+            mTestClasses = testClasses;
+        }
+
+        private void sendTestStatus(int status, String testClass, String testMethod) {
+            Bundle statusBundle = new Bundle();
+            statusBundle.putString(InstrumentationTestRunner.REPORT_KEY_NAME_CLASS, testClass);
+            statusBundle.putString(InstrumentationTestRunner.REPORT_KEY_NAME_TEST, testMethod);
+            sendStatus(status, statusBundle);
+        }
+
+        /** Run the tests. */
+        @Override
+        public void run() {
+            final HashMap<String, ResultsBundleGenerator.TestResult> finished =
+                    new HashMap<String, ResultsBundleGenerator.TestResult>();
+            final Object statusLock = new Object();
+
+            try {
+                TestStatusReceiver r = new TestStatusReceiver();
+                r.registerCallback(new TestStatusReceiver.StartCallback() {
+                    @Override
+                    public void testStarted(String testClass, String testMethod) {
+                        sendTestStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_START,
+                                testClass, testMethod);
+                        synchronized (statusLock) {
+                            statusLock.notify();
+                        }
+                    }
+                });
+                r.registerCallback(new TestStatusReceiver.PassCallback() {
+                    @Override
+                    public void testPassed(String testClass, String testMethod) {
+                        sendTestStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_OK, testClass,
+                                testMethod);
+                        synchronized (statusLock) {
+                            finished.put(testClass + "#" + testMethod,
+                                    ResultsBundleGenerator.TestResult.PASSED);
+                            statusLock.notify();
+                        }
+                    }
+                });
+                r.registerCallback(new TestStatusReceiver.FailCallback() {
+                    @Override
+                    public void testFailed(String testClass, String testMethod) {
+                        sendTestStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_ERROR,
+                                testClass, testMethod);
+                        synchronized (statusLock) {
+                            finished.put(testClass + "#" + testMethod,
+                                    ResultsBundleGenerator.TestResult.FAILED);
+                            statusLock.notify();
+                        }
+                    }
+                });
+                r.registerCallback(new TestStatusReceiver.HeartbeatCallback() {
+                    @Override
+                    public void heartbeat() {
+                        Log.i(TAG, "Heartbeat received.");
+                        synchronized (statusLock) {
+                            statusLock.notify();
+                        }
+                    }
+                });
+                r.register(getContext());
+
+                for (String t : mTestClasses) {
+                    Intent slaveIntent = new Intent();
+                    slaveIntent.setComponent(new ComponentName(
+                            mTargetPackage, OnDeviceInstrumentationBroker.class.getName()));
+                    slaveIntent.putExtra(
+                            OnDeviceInstrumentationBroker.EXTRA_INSTRUMENTATION_PACKAGE,
+                            mTargetPackage);
+                    slaveIntent.putExtra(
+                            OnDeviceInstrumentationBroker.EXTRA_INSTRUMENTATION_CLASS,
+                            mTargetClass);
+                    slaveIntent.putExtra(OnDeviceInstrumentationBroker.EXTRA_TEST, t);
+                    slaveIntent.putExtra(OnDeviceInstrumentationBroker.EXTRA_TARGET_ARGS,
+                            mTargetArgs);
+                    slaveIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+                    getContext().startActivity(slaveIntent);
+
+                    synchronized (statusLock) {
+                        while (!finished.containsKey(t)) {
+                            long waitStart = System.currentTimeMillis();
+                            statusLock.wait(TEST_WAIT_TIMEOUT);
+                            if (System.currentTimeMillis() - waitStart > TEST_WAIT_TIMEOUT) {
+                                Log.e(TAG, t + " has gone missing and is assumed to be dead.");
+                                finished.put(t, ResultsBundleGenerator.TestResult.FAILED);
+                                break;
+                            }
+                        }
+                    }
+                }
+                getContext().unregisterReceiver(r);
+
+            } catch (InterruptedException e) {
+                fail("Interrupted while running tests.", e);
+                return;
+            }
+            pass(new RobotiumBundleGenerator().generate(finished));
+        }
+
+    }
+
+    private void fail(String reason) {
+        Log.e(TAG, reason);
+        failImpl(reason);
+    }
+
+    private void fail(String reason, Exception e) {
+        Log.e(TAG, reason, e);
+        failImpl(reason);
+    }
+
+    private void failImpl(String reason) {
+        Bundle b = new Bundle();
+        b.putString("reason", reason);
+        finish(Activity.RESULT_CANCELED, b);
+    }
+
+    private void pass(Bundle results) {
+        finish(Activity.RESULT_OK, results);
+    }
+}
diff --git a/testing/android/native_test.gyp b/testing/android/native_test.gyp
index b26e01e..5993c43 100644
--- a/testing/android/native_test.gyp
+++ b/testing/android/native_test.gyp
@@ -30,7 +30,7 @@
           'target_name': 'native_test_jni_headers',
           'type': 'none',
           'sources': [
-            'native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java'
+            'native_test/java/src/org/chromium/native_test/NativeTestActivity.java'
           ],
           'variables': {
             'jni_gen_package': 'testing',
diff --git a/testing/android/native_test/BUILD.gn b/testing/android/native_test/BUILD.gn
index e0288f6..5df47fd 100644
--- a/testing/android/native_test/BUILD.gn
+++ b/testing/android/native_test/BUILD.gn
@@ -26,7 +26,7 @@
 # GYP: //testing/android/native_test.gyp:native_test_jni_headers
 generate_jni("native_test_jni_headers") {
   sources = [
-    "java/src/org/chromium/native_test/ChromeNativeTestActivity.java",
+    "java/src/org/chromium/native_test/NativeTestActivity.java",
   ]
   jni_package = "testing"
 }
diff --git a/testing/android/native_test/java/AndroidManifest.xml b/testing/android/native_test/java/AndroidManifest.xml
index 244f116..a92fb5f 100644
--- a/testing/android/native_test/java/AndroidManifest.xml
+++ b/testing/android/native_test/java/AndroidManifest.xml
@@ -19,10 +19,10 @@
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
-    <application android:label="ChromeNativeTests"
+    <application android:label="NativeTests"
             android:name="org.chromium.base.BaseChromiumApplication">
-        <activity android:name=".ChromeNativeTestActivity"
-                android:label="ChromeNativeTest"
+        <activity android:name=".NativeTestActivity"
+                android:label="NativeTest"
                 android:configChanges="orientation|keyboardHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -31,7 +31,7 @@
         </activity>
     </application>
 
-    <instrumentation android:name="org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner"
+    <instrumentation android:name="org.chromium.native_test.NativeTestInstrumentationTestRunner"
             android:targetPackage="org.chromium.native_test"
             android:label="Instrumentation entry point for org.chromium.native_test"/>
 
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java b/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java
deleted file mode 100644
index 4e1a067..0000000
--- a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java
+++ /dev/null
@@ -1,230 +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.native_test;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *  An Instrumentation that runs tests based on ChromeNativeTestActivity.
- */
-public class ChromeNativeTestInstrumentationTestRunner extends Instrumentation {
-    // TODO(jbudorick): Remove this extra when b/18981674 is fixed.
-    public static final String EXTRA_ONLY_OUTPUT_FAILURES =
-            "org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner."
-                    + "OnlyOutputFailures";
-
-    private static final String TAG = "ChromeNativeTestInstrumentationTestRunner";
-
-    private static final int ACCEPT_TIMEOUT_MS = 5000;
-    private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]+) .*");
-
-    private static interface ResultsBundleGenerator {
-        public Bundle generate(Map<String, TestResult> rawResults);
-    }
-
-    private String mCommandLineFile;
-    private String mCommandLineFlags;
-    private File mStdoutFile;
-    private Bundle mLogBundle;
-    private ResultsBundleGenerator mBundleGenerator;
-    private boolean mOnlyOutputFailures;
-
-    @Override
-    public void onCreate(Bundle arguments) {
-        mCommandLineFile = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE);
-        mCommandLineFlags = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
-        try {
-            mStdoutFile = File.createTempFile(
-                    ".temp_stdout_", ".txt", Environment.getExternalStorageDirectory());
-            Log.i(TAG, "stdout file created: " + mStdoutFile.getAbsolutePath());
-        } catch (IOException e) {
-            Log.e(TAG, "Unable to create temporary stdout file." + e.toString());
-            finish(Activity.RESULT_CANCELED, new Bundle());
-            return;
-        }
-        mLogBundle = new Bundle();
-        mBundleGenerator = new RobotiumBundleGenerator();
-        mOnlyOutputFailures = arguments.containsKey(EXTRA_ONLY_OUTPUT_FAILURES);
-        start();
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        Bundle results = runTests();
-        finish(Activity.RESULT_OK, results);
-    }
-
-    /** Runs the tests in the ChromeNativeTestActivity and returns a Bundle containing the results.
-     */
-    private Bundle runTests() {
-        Log.i(TAG, "Creating activity.");
-        Activity activityUnderTest = startNativeTestActivity();
-
-        Log.i(TAG, "Waiting for tests to finish.");
-        try {
-            while (!activityUnderTest.isFinishing()) {
-                Thread.sleep(100);
-            }
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Interrupted while waiting for activity to be destroyed: " + e.toString());
-        }
-
-        Log.i(TAG, "Getting results.");
-        Map<String, TestResult> results = parseResults(activityUnderTest);
-
-        Log.i(TAG, "Parsing results and generating output.");
-        return mBundleGenerator.generate(results);
-    }
-
-    /** Starts the ChromeNativeTestActivty.
-     */
-    private Activity startNativeTestActivity() {
-        Intent i = new Intent(Intent.ACTION_MAIN);
-        i.setComponent(new ComponentName(
-                "org.chromium.native_test",
-                "org.chromium.native_test.ChromeNativeTestActivity"));
-        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        if (mCommandLineFile != null) {
-            Log.i(TAG, "Passing command line file extra: " + mCommandLineFile);
-            i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
-        }
-        if (mCommandLineFlags != null) {
-            Log.i(TAG, "Passing command line flag extra: " + mCommandLineFlags);
-            i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
-        }
-        i.putExtra(ChromeNativeTestActivity.EXTRA_STDOUT_FILE, mStdoutFile.getAbsolutePath());
-        return startActivitySync(i);
-    }
-
-    private static enum TestResult {
-        PASSED, FAILED, ERROR, UNKNOWN
-    }
-
-    /**
-     *  Generates a map between test names and test results from the instrumented Activity's
-     *  output.
-     */
-    private Map<String, TestResult> parseResults(Activity activityUnderTest) {
-        Map<String, TestResult> results = new HashMap<String, TestResult>();
-
-        BufferedReader r = null;
-
-        try {
-            if (mStdoutFile == null || !mStdoutFile.exists()) {
-                Log.e(TAG, "Unable to find stdout file.");
-                return results;
-            }
-
-            r = new BufferedReader(new InputStreamReader(
-                    new BufferedInputStream(new FileInputStream(mStdoutFile))));
-
-            for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger");
-                    l = r.readLine()) {
-                Matcher m = RE_TEST_OUTPUT.matcher(l);
-                boolean isFailure = false;
-                if (m.matches()) {
-                    if (m.group(1).equals("RUN")) {
-                        results.put(m.group(2), TestResult.UNKNOWN);
-                    } else if (m.group(1).equals("FAILED")) {
-                        results.put(m.group(2), TestResult.FAILED);
-                        isFailure = true;
-                        mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
-                        sendStatus(0, mLogBundle);
-                    } else if (m.group(1).equals("OK")) {
-                        results.put(m.group(2), TestResult.PASSED);
-                    }
-                }
-
-                // TODO(jbudorick): mOnlyOutputFailures is a workaround for b/18981674. Remove it
-                // once that issue is fixed.
-                if (!mOnlyOutputFailures || isFailure) {
-                    mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
-                    sendStatus(0, mLogBundle);
-                }
-                Log.i(TAG, l);
-            }
-        } catch (FileNotFoundException e) {
-            Log.e(TAG, "Couldn't find stdout file file: " + e.toString());
-        } catch (IOException e) {
-            Log.e(TAG, "Error handling stdout file: " + e.toString());
-        } finally {
-            if (r != null) {
-                try {
-                    r.close();
-                } catch (IOException e) {
-                    Log.e(TAG, "Error while closing stdout reader.");
-                }
-            }
-            if (mStdoutFile != null) {
-                if (!mStdoutFile.delete()) {
-                    Log.e(TAG, "Unable to delete " + mStdoutFile.getAbsolutePath());
-                }
-            }
-        }
-        return results;
-    }
-
-    /**
-     * Creates a results bundle that emulates the one created by Robotium.
-     */
-    private static class RobotiumBundleGenerator implements ResultsBundleGenerator {
-        public Bundle generate(Map<String, TestResult> rawResults) {
-            Bundle resultsBundle = new Bundle();
-
-            int testsPassed = 0;
-            int testsFailed = 0;
-
-            for (Map.Entry<String, TestResult> entry : rawResults.entrySet()) {
-                switch (entry.getValue()) {
-                    case PASSED:
-                        ++testsPassed;
-                        break;
-                    case FAILED:
-                        // TODO(jbudorick): Remove this log message once AMP execution and
-                        // results handling has been stabilized.
-                        Log.d(TAG, "FAILED: " + entry.getKey());
-                        ++testsFailed;
-                        break;
-                    default:
-                        Log.w(TAG, "Unhandled: " + entry.getKey() + ", "
-                                + entry.getValue().toString());
-                        break;
-                }
-            }
-
-            StringBuilder resultBuilder = new StringBuilder();
-            if (testsFailed > 0) {
-                resultBuilder.append(
-                        "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size())
-                        + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0");
-            } else {
-                resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)");
-            }
-            resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
-                    resultBuilder.toString());
-            return resultsBundle;
-        }
-    }
-
-}
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
similarity index 88%
rename from testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
rename to testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
index 4a74877..e8c4055 100644
--- a/testing/android/native_test/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
@@ -9,9 +9,9 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
-import android.util.Log;
 
 import org.chromium.base.CommandLine;
+import org.chromium.base.Log;
 import org.chromium.base.PathUtils;
 import org.chromium.base.PowerMonitor;
 import org.chromium.base.ResourceExtractor;
@@ -24,15 +24,15 @@
  *  Our tests need to go up to our own java classes, which is not possible using
  *  the native activity class loader.
  */
-public class ChromeNativeTestActivity extends Activity {
+public class NativeTestActivity extends Activity {
     public static final String EXTRA_COMMAND_LINE_FILE =
-            "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile";
+            "org.chromium.native_test.NativeTestActivity.CommandLineFile";
     public static final String EXTRA_COMMAND_LINE_FLAGS =
-            "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags";
+            "org.chromium.native_test.NativeTestActivity.CommandLineFlags";
     public static final String EXTRA_STDOUT_FILE =
-            "org.chromium.native_test.ChromeNativeTestActivity.StdoutFile";
+            "org.chromium.native_test.NativeTestActivity.StdoutFile";
 
-    private static final String TAG = "ChromeNativeTestActivity";
+    private static final String TAG = Log.makeTag("native_test");
     private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread";
     // We post a delayed task to run tests so that we do not block onCreate().
     private static final long RUN_TESTS_DELAY_IN_MS = 300;
@@ -88,7 +88,7 @@
                 commandLineFilePath = Environment.getExternalStorageDirectory() + "/"
                         + commandLineFilePath;
             }
-            Log.i(TAG, "command line file path: " + commandLineFilePath);
+            Log.i(TAG, "command line file path: %s", commandLineFilePath);
         }
 
         String stdoutFilePath = getIntent().getStringExtra(EXTRA_STDOUT_FILE);
@@ -113,9 +113,9 @@
 
     private void loadLibraries() {
         for (String library : NativeLibraries.LIBRARIES) {
-            Log.i(TAG, "loading: " + library);
+            Log.i(TAG, "loading: %s", library);
             System.loadLibrary(library);
-            Log.i(TAG, "loaded: " + library);
+            Log.i(TAG, "loaded: %s", library);
         }
     }
 
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java
new file mode 100644
index 0000000..c5a4443
--- /dev/null
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java
@@ -0,0 +1,185 @@
+// 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.native_test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+
+import org.chromium.base.Log;
+import org.chromium.test.support.ResultsBundleGenerator;
+import org.chromium.test.support.RobotiumBundleGenerator;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *  An Instrumentation that runs tests based on NativeTestActivity.
+ */
+public class NativeTestInstrumentationTestRunner extends Instrumentation {
+    // TODO(jbudorick): Remove this extra when b/18981674 is fixed.
+    public static final String EXTRA_ONLY_OUTPUT_FAILURES =
+            "org.chromium.native_test.NativeTestInstrumentationTestRunner."
+                    + "OnlyOutputFailures";
+
+    private static final String TAG = Log.makeTag("native_test");
+
+    private static final int ACCEPT_TIMEOUT_MS = 5000;
+    private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]+) .*");
+
+    private String mCommandLineFile;
+    private String mCommandLineFlags;
+    private File mStdoutFile;
+    private Bundle mLogBundle;
+    private ResultsBundleGenerator mBundleGenerator;
+    private boolean mOnlyOutputFailures;
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        mCommandLineFile = arguments.getString(NativeTestActivity.EXTRA_COMMAND_LINE_FILE);
+        mCommandLineFlags = arguments.getString(NativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
+        try {
+            mStdoutFile = File.createTempFile(
+                    ".temp_stdout_", ".txt", Environment.getExternalStorageDirectory());
+            Log.i(TAG, "stdout file created: %s", mStdoutFile.getAbsolutePath());
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to create temporary stdout file.", e);
+            finish(Activity.RESULT_CANCELED, new Bundle());
+            return;
+        }
+        mLogBundle = new Bundle();
+        mBundleGenerator = new RobotiumBundleGenerator();
+        mOnlyOutputFailures = arguments.containsKey(EXTRA_ONLY_OUTPUT_FAILURES);
+        start();
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        Bundle results = runTests();
+        finish(Activity.RESULT_OK, results);
+    }
+
+    /** Runs the tests in the NativeTestActivity and returns a Bundle containing the results.
+     */
+    private Bundle runTests() {
+        Log.i(TAG, "Creating activity.");
+        Activity activityUnderTest = startNativeTestActivity();
+
+        Log.i(TAG, "Waiting for tests to finish.");
+        try {
+            while (!activityUnderTest.isFinishing()) {
+                Thread.sleep(100);
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while waiting for activity to be destroyed: ", e);
+        }
+
+        Log.i(TAG, "Getting results.");
+        Map<String, ResultsBundleGenerator.TestResult> results = parseResults(activityUnderTest);
+
+        Log.i(TAG, "Parsing results and generating output.");
+        return mBundleGenerator.generate(results);
+    }
+
+    /** Starts the NativeTestActivty.
+     */
+    private Activity startNativeTestActivity() {
+        Intent i = new Intent(Intent.ACTION_MAIN);
+        i.setComponent(new ComponentName(
+                "org.chromium.native_test",
+                "org.chromium.native_test.NativeTestActivity"));
+        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (mCommandLineFile != null) {
+            Log.i(TAG, "Passing command line file extra: %s", mCommandLineFile);
+            i.putExtra(NativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
+        }
+        if (mCommandLineFlags != null) {
+            Log.i(TAG, "Passing command line flag extra: %s", mCommandLineFlags);
+            i.putExtra(NativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
+        }
+        i.putExtra(NativeTestActivity.EXTRA_STDOUT_FILE, mStdoutFile.getAbsolutePath());
+        return startActivitySync(i);
+    }
+
+    /**
+     *  Generates a map between test names and test results from the instrumented Activity's
+     *  output.
+     */
+    private Map<String, ResultsBundleGenerator.TestResult> parseResults(
+            Activity activityUnderTest) {
+        Map<String, ResultsBundleGenerator.TestResult> results =
+                new HashMap<String, ResultsBundleGenerator.TestResult>();
+
+        BufferedReader r = null;
+
+        try {
+            if (mStdoutFile == null || !mStdoutFile.exists()) {
+                Log.e(TAG, "Unable to find stdout file.");
+                return results;
+            }
+
+            r = new BufferedReader(new InputStreamReader(
+                    new BufferedInputStream(new FileInputStream(mStdoutFile))));
+
+            for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger");
+                    l = r.readLine()) {
+                Matcher m = RE_TEST_OUTPUT.matcher(l);
+                boolean isFailure = false;
+                if (m.matches()) {
+                    if (m.group(1).equals("RUN")) {
+                        results.put(m.group(2), ResultsBundleGenerator.TestResult.UNKNOWN);
+                    } else if (m.group(1).equals("FAILED")) {
+                        results.put(m.group(2), ResultsBundleGenerator.TestResult.FAILED);
+                        isFailure = true;
+                        mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
+                        sendStatus(0, mLogBundle);
+                    } else if (m.group(1).equals("OK")) {
+                        results.put(m.group(2), ResultsBundleGenerator.TestResult.PASSED);
+                    }
+                }
+
+                // TODO(jbudorick): mOnlyOutputFailures is a workaround for b/18981674. Remove it
+                // once that issue is fixed.
+                if (!mOnlyOutputFailures || isFailure) {
+                    mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, l + "\n");
+                    sendStatus(0, mLogBundle);
+                }
+                Log.i(TAG, l);
+            }
+        } catch (FileNotFoundException e) {
+            Log.e(TAG, "Couldn't find stdout file file: ", e);
+        } catch (IOException e) {
+            Log.e(TAG, "Error handling stdout file: ", e);
+        } finally {
+            if (r != null) {
+                try {
+                    r.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "Error while closing stdout reader.", e);
+                }
+            }
+            if (mStdoutFile != null) {
+                if (!mStdoutFile.delete()) {
+                    Log.e(TAG, "Unable to delete %s", mStdoutFile.getAbsolutePath());
+                }
+            }
+        }
+        return results;
+    }
+
+}
diff --git a/testing/android/native_test/native_test_launcher.cc b/testing/android/native_test/native_test_launcher.cc
index 51edf36..d49ca11 100644
--- a/testing/android/native_test/native_test_launcher.cc
+++ b/testing/android/native_test/native_test_launcher.cc
@@ -25,7 +25,7 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "gtest/gtest.h"
-#include "jni/ChromeNativeTestActivity_jni.h"
+#include "jni/NativeTestActivity_jni.h"
 #include "testing/android/native_test/native_test_util.h"
 
 using testing::native_test_util::ArgsToArgv;
diff --git a/testing/android/on_device_instrumentation.gyp b/testing/android/on_device_instrumentation.gyp
new file mode 100644
index 0000000..12e0f35
--- /dev/null
+++ b/testing/android/on_device_instrumentation.gyp
@@ -0,0 +1,79 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'conditions': [
+    ['OS=="android"', {
+      'variables' : {
+        'driver_apk_name': 'OnDeviceInstrumentationDriver',
+        'driver_apk_path': '<(PRODUCT_DIR)/apks/<(driver_apk_name).apk'
+      },
+      'targets': [
+        {
+          'target_name': 'reporter_java',
+          'type': 'none',
+          'dependencies': ['../../base/base.gyp:base_java'],
+          'variables': {
+            'java_in_dir': '../../testing/android/reporter/java',
+          },
+          'includes': [
+            '../../build/java.gypi',
+          ],
+        },
+        {
+          'target_name': 'broker_java',
+          'type': 'none',
+          'variables': {
+            'java_in_dir': '../../testing/android/broker/java',
+          },
+          'includes': [
+            '../../build/java.gypi',
+          ],
+        },
+        {
+          'target_name': 'driver_apk',
+          'type': 'none',
+          'dependencies': [
+            'broker_java',
+            'reporter_java',
+            'appurify_support.gyp:appurify_support_java',
+          ],
+          'variables': {
+            'apk_name': '<(driver_apk_name)',
+            'final_apk_path': '<(driver_apk_path)',
+            'java_in_dir': '../../testing/android/driver/java',
+          },
+          'includes': [
+            '../../build/java_apk.gypi',
+          ],
+        },
+        {
+          # This emulates gn's datadeps fields, allowing other APKs to declare
+          # that they require that this APK be built without including the
+          # driver's code.
+          'target_name': 'require_driver_apk',
+          'type': 'none',
+          'actions': [
+            {
+              'action_name': 'require_<(driver_apk_name)',
+              'message': 'Making sure <(driver_apk_path) has been built.',
+              'variables': {
+                'required_file': '<(PRODUCT_DIR)/driver_apk/<(driver_apk_name).apk.required',
+              },
+              'inputs': [
+                '<(driver_apk_path)',
+              ],
+              'outputs': [
+                '<(required_file)',
+              ],
+              'action': [
+                'python', '../../build/android/gyp/touch.py', '<(required_file)',
+              ],
+            },
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/testing/android/reporter/BUILD.gn b/testing/android/reporter/BUILD.gn
new file mode 100644
index 0000000..7086a79
--- /dev/null
+++ b/testing/android/reporter/BUILD.gn
@@ -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.
+
+import("//build/config/android/rules.gni")
+
+# GYP: //testing/android/on_device_instrumentation.gyp:reporter_java
+android_library("reporter_java") {
+  chromium_code = true
+
+  deps = [
+    "//base:base_java",
+  ]
+  java_files = [
+    "java/src/org/chromium/test/reporter/TestStatusListener.java",
+    "java/src/org/chromium/test/reporter/TestStatusReceiver.java",
+    "java/src/org/chromium/test/reporter/TestStatusReporter.java",
+  ]
+}
diff --git a/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusListener.java b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusListener.java
new file mode 100644
index 0000000..6275418
--- /dev/null
+++ b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusListener.java
@@ -0,0 +1,78 @@
+// 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.test.reporter;
+
+import android.content.Context;
+import android.util.Log;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+
+/**
+ * A TestListener that reports when tests start, pass, or fail.
+ */
+public class TestStatusListener implements TestListener {
+
+    private static final String TAG = "TestStatusListener";
+
+    private boolean mFailed;
+    private final TestStatusReporter mReporter;
+
+    public TestStatusListener(Context context) {
+        mReporter = new TestStatusReporter(context);
+    }
+
+    /** Called when an error has occurred while running a test.
+
+        Note that an error usually means a problem with the test or test harness, not with
+        the code under test.
+
+        @param test The test in which the error occurred.
+        @param t The exception that was raised.
+     */
+    @Override
+    public void addError(Test test, Throwable t) {
+        Log.e(TAG, "Error while running " + test.toString(), t);
+        mFailed = true;
+    }
+
+    /** Called when a test has failed.
+
+        @param test The test in which the failure occurred.
+        @param t The exception that was raised.
+     */
+    public void addFailure(Test test, AssertionFailedError e) {
+        Log.e(TAG, "Failure while running " + test.toString(), e);
+        mFailed = true;
+    }
+
+    /** Called when a test has started.
+        @param test The test that started.
+     */
+    @Override
+    public void startTest(Test test) {
+        mFailed = false;
+        TestCase testCase = (TestCase) test;
+        mReporter.startHeartbeat();
+        mReporter.testStarted(testCase.getClass().getName(), testCase.getName());
+    }
+
+    /** Called when a test has ended.
+        @param test The test that ended.
+     */
+    @Override
+    public void endTest(Test test) {
+        TestCase testCase = (TestCase) test;
+        if (mFailed) {
+            mReporter.testFailed(testCase.getClass().getName(), testCase.getName());
+        } else {
+            mReporter.testPassed(testCase.getClass().getName(), testCase.getName());
+        }
+        mReporter.stopHeartbeat();
+    }
+
+}
diff --git a/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReceiver.java b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReceiver.java
new file mode 100644
index 0000000..e4af9b6
--- /dev/null
+++ b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReceiver.java
@@ -0,0 +1,128 @@
+// 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.test.reporter;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Receives test status broadcasts send from
+    {@link org.chromium.test.reporter.TestStatusReporter}.
+ */
+public class TestStatusReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "ResultReceiver";
+
+    private final List<FailCallback> mFailCallbacks = new ArrayList<FailCallback>();
+    private final List<HeartbeatCallback> mHeartbeatCallbacks = new ArrayList<HeartbeatCallback>();
+    private final List<PassCallback> mPassCallbacks = new ArrayList<PassCallback>();
+    private final List<StartCallback> mStartCallbacks = new ArrayList<StartCallback>();
+
+    /** An IntentFilter that matches the intents that this class can receive. */
+    private static final IntentFilter INTENT_FILTER;
+    static {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(TestStatusReporter.ACTION_HEARTBEAT);
+        filter.addAction(TestStatusReporter.ACTION_TEST_FAILED);
+        filter.addAction(TestStatusReporter.ACTION_TEST_PASSED);
+        filter.addAction(TestStatusReporter.ACTION_TEST_STARTED);
+        try {
+            filter.addDataType(TestStatusReporter.DATA_TYPE_HEARTBEAT);
+            filter.addDataType(TestStatusReporter.DATA_TYPE_RESULT);
+        } catch (IntentFilter.MalformedMimeTypeException e) {
+            Log.wtf(TAG, "Invalid MIME type", e);
+        }
+        INTENT_FILTER = filter;
+    }
+
+    /** A callback used when a test has failed. */
+    public interface FailCallback {
+        void testFailed(String testClass, String testMethod);
+    }
+
+    /** A callback used when a heartbeat is received. */
+    public interface HeartbeatCallback {
+        void heartbeat();
+    }
+
+    /** A callback used when a test has passed. */
+    public interface PassCallback {
+        void testPassed(String testClass, String testMethod);
+    }
+
+    /** A callback used when a test has started. */
+    public interface StartCallback {
+        void testStarted(String testClass, String testMethod);
+    }
+
+    /** Register a callback for when a test has failed. */
+    public void registerCallback(FailCallback c) {
+        mFailCallbacks.add(c);
+    }
+
+    /** Register a callback for when a heartbeat is received. */
+    public void registerCallback(HeartbeatCallback c) {
+        mHeartbeatCallbacks.add(c);
+    }
+
+    /** Register a callback for when a test has passed. */
+    public void registerCallback(PassCallback c) {
+        mPassCallbacks.add(c);
+    }
+
+    /** Register a callback for when a test has started. */
+    public void registerCallback(StartCallback c) {
+        mStartCallbacks.add(c);
+    }
+
+    /** Register this receiver using the provided context. */
+    public void register(Context c) {
+        c.registerReceiver(this, INTENT_FILTER);
+    }
+
+    /** Receive a broadcast intent.
+     *
+     * @param context The Context in which the receiver is running.
+     * @param intent The intent received.
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String testClass = intent.getStringExtra(TestStatusReporter.EXTRA_TEST_CLASS);
+        String testMethod = intent.getStringExtra(TestStatusReporter.EXTRA_TEST_METHOD);
+
+        switch (intent.getAction()) {
+            case TestStatusReporter.ACTION_TEST_STARTED:
+                for (StartCallback c : mStartCallbacks) {
+                    c.testStarted(testClass, testMethod);
+                }
+                break;
+            case TestStatusReporter.ACTION_TEST_PASSED:
+                for (PassCallback c : mPassCallbacks) {
+                    c.testPassed(testClass, testMethod);
+                }
+                break;
+            case TestStatusReporter.ACTION_TEST_FAILED:
+                for (FailCallback c : mFailCallbacks) {
+                    c.testFailed(testClass, testMethod);
+                }
+                break;
+            case TestStatusReporter.ACTION_HEARTBEAT:
+                for (HeartbeatCallback c : mHeartbeatCallbacks) {
+                    c.heartbeat();
+                }
+                break;
+            default:
+                Log.e(TAG, "Unrecognized intent received: " + intent.toString());
+                break;
+        }
+    }
+
+}
+
diff --git a/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReporter.java b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReporter.java
new file mode 100644
index 0000000..6ac7312
--- /dev/null
+++ b/testing/android/reporter/java/src/org/chromium/test/reporter/TestStatusReporter.java
@@ -0,0 +1,83 @@
+// 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.test.reporter;
+
+import android.content.Context;
+import android.content.Intent;
+
+import org.chromium.base.ThreadUtils;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Broadcasts test status to any listening {@link org.chromium.test.reporter.TestStatusReceiver}.
+ */
+public class TestStatusReporter {
+
+    public static final String ACTION_HEARTBEAT =
+            "org.chromium.test.reporter.TestStatusReporter.HEARTBEAT";
+    public static final String ACTION_TEST_STARTED =
+            "org.chromium.test.reporter.TestStatusReporter.TEST_STARTED";
+    public static final String ACTION_TEST_PASSED =
+            "org.chromium.test.reporter.TestStatusReporter.TEST_PASSED";
+    public static final String ACTION_TEST_FAILED =
+            "org.chromium.test.reporter.TestStatusReporter.TEST_FAILED";
+    public static final String DATA_TYPE_HEARTBEAT = "org.chromium.test.reporter/heartbeat";
+    public static final String DATA_TYPE_RESULT = "org.chromium.test.reporter/result";
+    public static final String EXTRA_TEST_CLASS =
+            "org.chromium.test.reporter.TestStatusReporter.TEST_CLASS";
+    public static final String EXTRA_TEST_METHOD =
+            "org.chromium.test.reporter.TestStatusReporter.TEST_METHOD";
+
+    public static final int HEARTBEAT_INTERVAL_MS = 5000;
+
+    private final Context mContext;
+    private final AtomicBoolean mKeepBeating = new AtomicBoolean(false);
+
+    public TestStatusReporter(Context c) {
+        mContext = c;
+    }
+
+    public void startHeartbeat() {
+        mKeepBeating.set(true);
+        Runnable heartbeat = new Runnable() {
+            @Override
+            public void run() {
+                Intent i = new Intent(ACTION_HEARTBEAT);
+                i.setType(DATA_TYPE_HEARTBEAT);
+                mContext.sendBroadcast(i);
+                if (mKeepBeating.get()) {
+                    ThreadUtils.postOnUiThreadDelayed(this, HEARTBEAT_INTERVAL_MS);
+                }
+            }
+        };
+        ThreadUtils.postOnUiThreadDelayed(heartbeat, HEARTBEAT_INTERVAL_MS);
+    }
+
+    public void testStarted(String testClass, String testMethod) {
+        sendBroadcast(testClass, testMethod, ACTION_TEST_STARTED);
+    }
+
+    public void testPassed(String testClass, String testMethod) {
+        sendBroadcast(testClass, testMethod, ACTION_TEST_PASSED);
+    }
+
+    public void testFailed(String testClass, String testMethod) {
+        sendBroadcast(testClass, testMethod, ACTION_TEST_FAILED);
+    }
+
+    public void stopHeartbeat() {
+        mKeepBeating.set(false);
+    }
+
+    private void sendBroadcast(String testClass, String testMethod, String action) {
+        Intent i = new Intent(action);
+        i.setType(DATA_TYPE_RESULT);
+        i.putExtra(EXTRA_TEST_CLASS, testClass);
+        i.putExtra(EXTRA_TEST_METHOD, testMethod);
+        mContext.sendBroadcast(i);
+    }
+
+}
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index e7df4ed..177b686 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -58,7 +58,51 @@
   },
   "Linux ChromiumOS GN (dbg)": {
     "additional_compile_targets": [
-      "net_unittests"
+      "accessibility_unittests",
+      "app_list_unittests",
+      "aura_unittests",
+      "browser_tests",
+      "cacheinvalidation_unittests",
+      "chromedriver_unittests",
+      "chromeos_unittests",
+      "content_unittests",
+      "crypto_unittests",
+      "dbus_unittests",
+      "device_unittests",
+      "display_unittests",
+      "events_unittests",
+      "extensions_browsertests",
+      "extensions_unittests",
+      "gcm_unit_tests",
+      "gfx_unittests",
+      "gn_unittests",
+      "google_apis_unittests",
+      "gpu_unittests",
+      "interactive_ui_tests",
+      "ipc_tests",
+      "jingle_unittests",
+      "media_unittests",
+      "mojo_common_unittests",
+      "mojo_public_bindings_unittests",
+      "mojo_public_environment_unittests",
+      "mojo_public_system_unittests",
+      "mojo_public_utility_unittests",
+      "mojo_system_unittests",
+      "net_unittests",
+      "ppapi_unittests",
+      "printing_unittests",
+      "remoting_unittests",
+      "sandbox_linux_unittests",
+      "skia_unittests",
+      "sql_unittests",
+      "sync_unit_tests",
+      "ui_base_unittests",
+      "ui_chromeos_unittests",
+      "ui_touch_selection_unittests",
+      "unit_tests",
+      "url_unittests",
+      "views_unittests",
+      "wm_unittests"
     ],
     "gtest_tests": [
       {
@@ -173,6 +217,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -358,6 +405,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -539,6 +589,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 3b3c8fe..2711337 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4,14 +4,14 @@
       {
         "args": [
           "--enable-browser-side-navigation",
-          "--gtest_filter=-BatteryMonitorImplTest.BatteryManagerDefaultValues:BatteryMonitorImplTest.BatteryManagerResolvePromise:BatteryMonitorImplTest.BatteryManagerWithEventListener:BookmarkletTest.DocumentWrite:BookmarkletTest.NonEmptyResult:BookmarkletTest.Redirect:BookmarkletTest.RedirectVoided:ChildProcessLauncherBrowserTest.ChildSpawnFail:CrossProcessFrameTreeBrowserTest.CreateCrossProcessSubframeProxies:CrossProcessFrameTreeBrowserTest.OriginSetOnCrossProcessNavigations:CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DatabaseTest.ReloadPage:DeviceInertialSensorBrowserTest.LightOneOffInfintyTest:DeviceInertialSensorBrowserTest.LightTest:DeviceInertialSensorBrowserTest.MotionNullTest:DeviceInertialSensorBrowserTest.MotionTest:DeviceInertialSensorBrowserTest.OrientationNullTest:DeviceInertialSensorBrowserTest.OrientationTest:DOMStorageBrowserTest.SanityCheck:DOMStorageBrowserTest.SanityCheckIncognito:DownloadContentTest.CancelAtFinalRename:DownloadContentTest.CancelAtRelease:DownloadContentTest.CancelInterruptedDownload:DownloadContentTest.CancelResumingDownload:DownloadContentTest.DownloadCancelled:DownloadContentTest.DownloadGZipWithNoContent:DownloadContentTest.DownloadOctetStream:DownloadContentTest.MultiDownload:DownloadContentTest.RemoveDownload:DownloadContentTest.RemoveResumingDownload:DownloadContentTest.ResumeInterruptedDownload:DownloadContentTest.ResumeInterruptedDownloadBadPrecondition:DownloadContentTest.ResumeInterruptedDownloadNoRange:DownloadContentTest.ResumeInterruptedDownloadNoVerifiers:DownloadContentTest.ResumeWithDeletedFile:DownloadContentTest.ResumeWithFileFinalRenameError:DownloadContentTest.ResumeWithFileInitError:DownloadContentTest.ResumeWithFileIntermediateRenameError:DownloadContentTest.ShutdownAtRelease:DownloadContentTest.ShutdownInProgress:File/MediaTest.VideoBearOpusOgg/0:File/MediaTest.VideoBearOpusWebm/0:File/MediaTest.VideoBearSilentTheora/0:File/MediaTest.VideoBearSilentWebm/0:File/MediaTest.VideoBearTheora/0:File/MediaTest.VideoBearWavAlaw/0:File/MediaTest.VideoBearWavMulaw/0:File/MediaTest.VideoBearWavPcm/0:File/MediaTest.VideoBearWavPcm192kHz/0:File/MediaTest.VideoBearWavPcm3kHz/0:File/MediaTest.VideoBearWebm/0:File/MediaTest.VideoTulipWebm/0:FileSystemBrowserTest.CreateTest:FileSystemBrowserTest.RequestTest:FileSystemBrowserTestWithLowQuota.QuotaTest:FrameTreeBrowserTest.FrameTreeAfterCrash:FrameTreeBrowserTest.SandboxFlagsSetForChildFrames:IndexedDBBrowserTest.BlobsCountAgainstQuota:IndexedDBBrowserTest.CallbackAccounting:IndexedDBBrowserTest.CanDeleteWhenOverQuotaTest:IndexedDBBrowserTest.ConnectionsClosedOnTabClose:IndexedDBBrowserTest.CursorPrefetch:IndexedDBBrowserTest.CursorTest:IndexedDBBrowserTest.CursorTestIncognito:IndexedDBBrowserTest.DatabaseTest:IndexedDBBrowserTest.DeleteCompactsBackingStore:IndexedDBBrowserTest.DeleteForOriginDeletesBlobs:IndexedDBBrowserTest.DiskFullOnCommit:IndexedDBBrowserTest.DoesntHangTest:IndexedDBBrowserTest.EmptyBlob:IndexedDBBrowserTest.ForceCloseEventTest:IndexedDBBrowserTest.IndexTest:IndexedDBBrowserTest.KeyPathTest:IndexedDBBrowserTest.KeyTypesTest:IndexedDBBrowserTest.LevelDBLogFileTest:IndexedDBBrowserTest.NullKeyPathPersistence:IndexedDBBrowserTest.ObjectStoreTest:IndexedDBBrowserTest.PRE_NullKeyPathPersistence:IndexedDBBrowserTest.PRE_PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.TransactionGetTest:IndexedDBBrowserTest.TransactionTest:IndexedDBBrowserTest.VersionChangeCrashResilience:IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest:IndexedDBBrowserTestWithCorruptLevelDB.DestroyTest:IndexedDBBrowserTestWithGCExposed.BlobDidAck:IndexedDBBrowserTestWithGCExposed.BlobDidAckPrefetch:IndexedDBBrowserTestWithGCExposed.DatabaseCallbacksTest:IndexedDBBrowserTestWithLowQuota.QuotaTest:IndexedDBBrowserTestWithMissingSSTFile.DestroyTest:IndexedDBBrowserTestWithVersion0Schema.MigrationTest:IndexedDBBrowserTestWithVersion123456Schema.DestroyTest:IndexedDBBrowserTestWithVersion987654SSVData.DestroyTest:ManifestBrowserTest.DummyManifest:ManifestBrowserTest.DynamicManifest:ManifestBrowserTest.ParseErrorManifest:ManifestBrowserTest.ParsingErrorsManifest:MediaCanPlayTypeTest.CodecSupportTest_Avc1Variants:MediaCanPlayTypeTest.CodecSupportTest_Avc3Variants:MediaCanPlayTypeTest.CodecSupportTest_AvcLevels:MediaCanPlayTypeTest.CodecSupportTest_HLS:MediaCanPlayTypeTest.CodecSupportTest_mp3:MediaCanPlayTypeTest.CodecSupportTest_mp4:MediaCanPlayTypeTest.CodecSupportTest_Mp4aVariants:MediaCanPlayTypeTest.CodecSupportTest_ogg:MediaCanPlayTypeTest.CodecSupportTest_wav:MediaCanPlayTypeTest.CodecSupportTest_webm:MediaTest.Navigate:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.CorrectLengthWithNewTabNavigatingFromWebUI:NavigationControllerBrowserTest.DontIgnoreBackAfterNavEntryLimit:NavigationControllerBrowserTest.ErrorPageReplacement:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.SubframeOnEmptyPage:OutOfProcessPPAPITest.InputEvent:OutOfProcessPPAPITest.MediaStreamAudioTrack:OutOfProcessPPAPITest.MediaStreamVideoTrack:RendererAccessibilityTest.AccessibilityMessagesQueueWhileSwappedOut:RenderFrameHostImplBrowserTest.IsFocused_AtLoad:RenderFrameHostImplBrowserTest.IsFocused_Widget:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.ClickLinkAfter204Error:RenderFrameHostManagerTest.DisownSubframeOpener:RenderFrameHostManagerTest.DontPreemptNavigationWithFrameTreeUpdate:RenderFrameHostManagerTest.ForceSwapAfterWebUIBindings:RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed:RenderFrameHostManagerTest.NoScriptAccessAfterSwapOut:RenderFrameHostManagerTest.RendererDebugURLsDontSwap:RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation:RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation:RenderFrameHostManagerTest.ShowLoadingURLUntilSpoof:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.InsertCharacters:RenderViewImplTest.NavigateFrame:RenderViewImplTest.NavigationStartOverride:RenderViewImplTest.OnHandleKeyboardEvent:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:ResourceDispatcherHostBrowserTest.CrossSiteAfterCrash:ResourceDispatcherHostBrowserTest.CrossSiteNoUnloadOn204:ResourceFetcherTests.ResourceFetcher404:ResourceFetcherTests.ResourceFetcherDeletedInCallback:ResourceFetcherTests.ResourceFetcherDidFail:ResourceFetcherTests.ResourceFetcherDownload:ResourceFetcherTests.ResourceFetcherPost:ResourceFetcherTests.ResourceFetcherSetHeader:ResourceFetcherTests.ResourceFetcherTimeout:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SessionHistoryTest.LocationReplace:SitePerProcessAccessibilityBrowserTest.CrossSiteIframeAccessibility:SitePerProcessBrowserTest.CleanupCrossSiteIframe:SitePerProcessBrowserTest.CompositorFrameSwapped:SitePerProcessBrowserTest.CreateProxiesForNewFrames:SitePerProcessBrowserTest.CrossSiteDidStopLoading:SitePerProcessBrowserTest.CrossSiteIframe:SitePerProcessBrowserTest.DynamicSandboxFlags:SitePerProcessBrowserTest.DynamicSandboxFlagsRemoteToLocal:SitePerProcessBrowserTest.KillingRendererClearsDescendantProxies:SitePerProcessBrowserTest.NavigateRemoteFrame:SitePerProcessBrowserTest.NavigateRemoteFrameToBlankAndDataURLs:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcessWithSubtree:SitePerProcessBrowserTest.NavigateWithSiblingRemoteFrame:SitePerProcessBrowserTest.OriginReplication:SitePerProcessBrowserTest.ProxyCreationSkipsSubtree:SitePerProcessBrowserTest.RFPHDestruction:SitePerProcessBrowserTest.RestrictFrameDetach:SitePerProcessBrowserTest.SandboxFlagsReplication:SitePerProcessBrowserTest.SubframePostMessage:SitePerProcessDevToolsBrowserTest.CrossSiteIframeAgentHost:SpeechRecognitionBrowserTest.OneShotRecognition:StatsTableBrowserTest.StartWithStatTable:TransitionBrowserTest.NormalNavigationNotDeferred:TransitionBrowserTest.TransitionNavigationDataIsCleared:TransitionBrowserTest.TransitionNavigationIsDeferred:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsImplBrowserTest.GetSizeForNewRenderView:WebContentsViewAuraTest.ScreenshotForSwappedOutRenderViews:WebUIMojoTest.EndToEndPing:WorkerTest.IncognitoSharedWorkers:WorkerTest.MultipleSharedWorkers:WorkerTest.MultipleWorkers:WorkerTest.PassMessagePortToSharedWorker:WorkerTest.PassMessagePortToSharedWorkerDontWaitForConnect:WorkerTest.SharedWorkerTlsClientAuth:WorkerTest.SingleSharedWorker:WorkerTest.SingleWorker:WorkerTest.WorkerTlsClientAuth"
+          "--gtest_filter=-BookmarkletTest.DocumentWrite:BookmarkletTest.NonEmptyResult:BookmarkletTest.Redirect:BookmarkletTest.RedirectVoided:ChildProcessLauncherBrowserTest.ChildSpawnFail:CrossProcessFrameTreeBrowserTest.CreateCrossProcessSubframeProxies:CrossProcessFrameTreeBrowserTest.OriginSetOnCrossProcessNavigations:CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DownloadContentTest.CancelAtFinalRename:DownloadContentTest.CancelAtRelease:DownloadContentTest.CancelInterruptedDownload:DownloadContentTest.CancelResumingDownload:DownloadContentTest.DownloadCancelled:DownloadContentTest.DownloadGZipWithNoContent:DownloadContentTest.DownloadOctetStream:DownloadContentTest.MultiDownload:DownloadContentTest.RemoveDownload:DownloadContentTest.RemoveResumingDownload:DownloadContentTest.ResumeInterruptedDownload:DownloadContentTest.ResumeInterruptedDownloadBadPrecondition:DownloadContentTest.ResumeInterruptedDownloadNoRange:DownloadContentTest.ResumeInterruptedDownloadNoVerifiers:DownloadContentTest.ResumeWithDeletedFile:DownloadContentTest.ResumeWithFileFinalRenameError:DownloadContentTest.ResumeWithFileInitError:DownloadContentTest.ResumeWithFileIntermediateRenameError:DownloadContentTest.ShutdownAtRelease:DownloadContentTest.ShutdownInProgress:FrameTreeBrowserTest.SandboxFlagsSetForChildFrames:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.ErrorPageReplacement:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.SubframeOnEmptyPage:RFHMProcessPerTabTest.BackFromWebUI:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.DisownOpener:RenderFrameHostManagerTest.DisownSubframeOpener:RenderFrameHostManagerTest.DontPreemptNavigationWithFrameTreeUpdate:RenderFrameHostManagerTest.NoScriptAccessAfterSwapOut:RenderFrameHostManagerTest.RendererDebugURLsDontSwap:RenderFrameHostManagerTest.ShowLoadingURLUntilSpoof:RenderFrameHostManagerTest.SwappedOutViewHasCorrectVisibilityState:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.NavigationStartOverride:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SitePerProcessAccessibilityBrowserTest.CrossSiteIframeAccessibility:SitePerProcessBrowserTest.CleanupCrossSiteIframe:SitePerProcessBrowserTest.CompositorFrameSwapped:SitePerProcessBrowserTest.CreateProxiesForNewFrames:SitePerProcessBrowserTest.CrossSiteDidStopLoading:SitePerProcessBrowserTest.CrossSiteIframe:SitePerProcessBrowserTest.DynamicSandboxFlags:SitePerProcessBrowserTest.DynamicSandboxFlagsRemoteToLocal:SitePerProcessBrowserTest.KillingRendererClearsDescendantProxies:SitePerProcessBrowserTest.NavigateRemoteFrame:SitePerProcessBrowserTest.NavigateRemoteFrameToBlankAndDataURLs:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcessWithSubtree:SitePerProcessBrowserTest.NavigateWithSiblingRemoteFrame:SitePerProcessBrowserTest.NavigatingToKilledProcessRestoresAllProxies:SitePerProcessBrowserTest.OriginReplication:SitePerProcessBrowserTest.OriginUpdatesReachProxies:SitePerProcessBrowserTest.ProxyCreationSkipsSubtree:SitePerProcessBrowserTest.RFPHDestruction:SitePerProcessBrowserTest.RestrictFrameDetach:SitePerProcessBrowserTest.SandboxFlagsReplication:SitePerProcessBrowserTest.SubframePostMessage:SitePerProcessDevToolsBrowserTest.CrossSiteIframeAgentHost:TransitionBrowserTest.NormalNavigationNotDeferred:TransitionBrowserTest.TransitionNavigationDataIsCleared:TransitionBrowserTest.TransitionNavigationIsDeferred:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsImplBrowserTest.GetSizeForNewRenderView:WebContentsViewAuraTest.OverscrollScreenshot:WebContentsViewAuraTest.ReplaceStateReloadPushState:WebUIMojoTest.EndToEndPing:WorkerTest.IncognitoSharedWorkers"
         ],
         "test": "content_browsertests"
       },
       {
         "args": [
           "--enable-browser-side-navigation",
-          "--gtest_filter=-NavigationControllerTest.CopyRestoredStateAndNavigate:NavigationControllerTest.LoadURL_AbortDoesntCancelPending:NavigationControllerTest.LoadURL_IgnorePreemptsPending:NavigationControllerTest.ShowRendererURLAfterFailUntilModified:NavigationControllerTest.ShowRendererURLInNewTabUntilModified:RenderFrameHostManagerTest.CancelPendingProperlyDeletesOrSwaps:RenderFrameHostManagerTest.NavigateWithEarlyClose:RenderFrameHostManagerTest.PageDoesBackAndReload:RenderViewHostTest.ResetUnloadOnReload:ResourceDispatcherHostTest.TransferNavigationHtml:ResourceDispatcherHostTest.TransferNavigationText:ResourceDispatcherHostTest.TransferNavigationWithProcessCrash:ResourceDispatcherHostTest.TransferNavigationWithTwoRedirects:ResourceDispatcherHostTest.TransferTwoNavigationsHtml:WebContentsImplTest.ActiveContentsCountChangeBrowsingInstance:WebContentsImplTest.CrossSiteNavigationBackPreempted:WebContentsImplTest.CrossSiteNavigationPreempted:WebContentsImplTest.CrossSiteNotPreemptedDuringBeforeUnload:WebContentsImplTest.NoEarlyStop:WebContentsImplTest.ShowInterstitialCrashRendererThenGoBack:WebContentsImplTest.ShowInterstitialFromBrowserNewNavigationProceed:WebContentsImplTest.ShowInterstitialThenGoBack"
+          "--gtest_filter=-NavigationControllerTest.CopyRestoredStateAndNavigate:RenderFrameHostManagerTest.CancelPendingProperlyDeletesOrSwaps:RenderFrameHostManagerTest.PageDoesBackAndReload:RenderViewHostTest.ResetUnloadOnReload:ResourceDispatcherHostTest.TransferNavigationHtml:ResourceDispatcherHostTest.TransferNavigationText:ResourceDispatcherHostTest.TransferNavigationWithProcessCrash:ResourceDispatcherHostTest.TransferNavigationWithTwoRedirects:ResourceDispatcherHostTest.TransferTwoNavigationsHtml:WebContentsImplTest.CrossSiteNavigationBackPreempted:WebContentsImplTest.CrossSiteNotPreemptedDuringBeforeUnload:WebContentsImplTest.NoEarlyStop:WebContentsImplTest.ShowInterstitialCrashRendererThenGoBack:WebContentsImplTest.ShowInterstitialFromBrowserNewNavigationProceed:WebContentsImplTest.ShowInterstitialThenGoBack"
         ],
         "test": "content_unittests"
       }
@@ -53,6 +53,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "net_unittests"
       },
       {
@@ -138,6 +141,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "message_center_unittests"
       },
       {
@@ -306,6 +312,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -467,6 +476,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -518,9 +530,15 @@
         "test": "app_list_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "browser_tests"
       },
       {
@@ -539,12 +557,18 @@
         "test": "components_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "content_browsertests"
       },
       {
         "test": "content_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "crypto_unittests"
       },
       {
@@ -563,6 +587,9 @@
         "test": "gpu_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "interactive_ui_tests"
       },
       {
@@ -578,6 +605,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -596,6 +626,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "net_unittests"
       },
       {
@@ -626,6 +659,9 @@
         "test": "ui_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "unit_tests"
       },
       {
@@ -656,9 +692,15 @@
         "test": "app_list_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "browser_tests"
       },
       {
@@ -677,12 +719,18 @@
         "test": "components_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "content_browsertests"
       },
       {
         "test": "content_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "crypto_unittests"
       },
       {
@@ -701,6 +749,9 @@
         "test": "gpu_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "interactive_ui_tests"
       },
       {
@@ -716,6 +767,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -734,6 +788,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "net_unittests"
       },
       {
@@ -764,6 +821,9 @@
         "test": "ui_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "unit_tests"
       },
       {
@@ -854,6 +914,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "net_unittests"
       },
       {
@@ -966,6 +1029,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "net_unittests"
       },
       {
@@ -1085,6 +1151,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1210,6 +1279,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1335,6 +1407,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1460,6 +1535,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1585,6 +1663,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1710,6 +1791,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1835,6 +1919,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1987,6 +2074,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -2152,6 +2242,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -2323,6 +2416,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -2488,6 +2584,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -2571,7 +2670,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
+          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
         ],
         "test": "browser_tests"
       },
@@ -2601,7 +2700,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
+          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*"
         ],
         "test": "browser_tests"
       },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 88acb35..2a54542 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -10,6 +10,10 @@
       {
         "name": "webview_licenses",
         "script": "webview_licenses.py"
+      },
+      {
+        "name": "telemetry_perf_unittests",
+        "script": "telemetry_perf_unittests.py"
       }
     ]
   },
@@ -18,6 +22,10 @@
       {
         "name": "webview_licenses",
         "script": "webview_licenses.py"
+      },
+      {
+        "name": "telemetry_perf_unittests",
+        "script": "telemetry_perf_unittests.py"
       }
     ]
   },
@@ -132,17 +140,13 @@
       "gn_unittests",
       "google_apis_unittests",
       "gpu_unittests",
+      "html_viewer_unittests",
       "interactive_ui_tests",
       "ipc_mojo_unittests",
       "ipc_tests",
       "jingle_unittests",
+      "mandoline:all",
       "media_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "nacl_loader_unittests",
       "net_unittests",
       "ppapi_unittests",
@@ -157,14 +161,11 @@
       "ui_touch_selection_unittests",
       "unit_tests",
       "url_unittests",
+      "view_manager_service_unittests",
       "views_unittests",
       "wm_unittests"
     ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
-    ]
+    "gtest_tests": []
   },
   "Linux GN (dbg)": {
     "additional_compile_targets": [
@@ -196,13 +197,8 @@
       "ipc_mojo_unittests",
       "ipc_tests",
       "jingle_unittests",
+      "mandoline:all",
       "media_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "net_unittests",
       "ppapi_unittests",
       "printing_unittests",
@@ -376,6 +372,12 @@
         "test": "media_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -630,6 +632,12 @@
         "test": "media_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -874,6 +882,12 @@
         "test": "media_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 8883601..58a4df2 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -190,6 +190,12 @@
         "test": "message_center_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -389,6 +395,12 @@
         "test": "message_center_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -588,6 +600,12 @@
         "test": "message_center_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -788,6 +806,12 @@
         "test": "message_center_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index dc1a9d7..8b94908 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -103,6 +103,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -267,6 +270,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -427,6 +433,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index dcdfe7c..132f87b 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -91,6 +91,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -266,6 +269,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -392,6 +398,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -496,6 +505,9 @@
         "test": "media_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index f3ad4ca..3c71c4d 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -240,6 +240,15 @@
     "scripts": [
       {
         "args": [
+          "angle_perftests",
+          "--test-launcher-print-test-stdio=always",
+          "--test-launcher-jobs=1"
+        ],
+        "name": "angle_perftests",
+        "script": "gtest_perf_test.py"
+      },
+      {
+        "args": [
           "performance_browser_tests",
           "--test-launcher-print-test-stdio=always",
           "--gtest_filter=TabCapturePerformanceTest.*:CastV2PerformanceTest.*",
@@ -255,6 +264,15 @@
     "scripts": [
       {
         "args": [
+          "angle_perftests",
+          "--test-launcher-print-test-stdio=always",
+          "--test-launcher-jobs=1"
+        ],
+        "name": "angle_perftests",
+        "script": "gtest_perf_test.py"
+      },
+      {
+        "args": [
           "performance_browser_tests",
           "--test-launcher-print-test-stdio=always",
           "--gtest_filter=TabCapturePerformanceTest.*:CastV2PerformanceTest.*",
@@ -287,7 +305,6 @@
         "args": [
           "angle_perftests",
           "--test-launcher-print-test-stdio=always",
-          "--gtest_filter=DrawCallPerf*",
           "--test-launcher-jobs=1"
         ],
         "name": "angle_perftests",
@@ -337,18 +354,6 @@
     ]
   },
   "Win 8 Perf (2)": {
-    "scripts": [
-      {
-        "args": [
-          "performance_browser_tests",
-          "--test-launcher-print-test-stdio=always",
-          "--gtest_filter=TabCapturePerformanceTest.*:CastV2PerformanceTest.*",
-          "--test-launcher-jobs=1",
-          "--enable-gpu"
-        ],
-        "name": "performance_browser_tests",
-        "script": "gtest_perf_test.py"
-      }
-    ]
+    "scripts": []
   }
 }
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index 5742add..e0bae2f 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -135,6 +135,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -310,6 +313,9 @@
         "test": "message_center_unittests"
       },
       {
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index ca0ab23..f349a2e 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -130,6 +130,12 @@
         "test": "media_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -371,6 +377,12 @@
         "test": "message_center_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -500,14 +512,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -562,14 +569,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -749,6 +751,12 @@
         "test": "message_center_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -977,6 +985,12 @@
         "test": "media_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "mojo_common_unittests"
       },
       {
@@ -1131,14 +1145,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -1193,14 +1202,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -1362,6 +1366,12 @@
         "test": "media_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
diff --git a/testing/buildbot/chromium_memory_trybot.json b/testing/buildbot/chromium_memory_trybot.json
index c58d2de..f17cb08 100644
--- a/testing/buildbot/chromium_memory_trybot.json
+++ b/testing/buildbot/chromium_memory_trybot.json
@@ -85,6 +85,12 @@
     },
     {
       "swarming": {
+        "can_use_on_swarming_builders": true
+      },
+      "test": "midi_unittests"
+    },
+    {
+      "swarming": {
         "can_use_on_swarming_builders": true,
         "shards": 2
       },
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index d42d551..68735d8 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -213,6 +213,12 @@
       },
       "test": "message_center_unittests"
     },
+    {
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      },
+      "test": "midi_unittests"
+    },
     "mojo_common_unittests",
     "mojo_public_bindings_unittests",
     "mojo_public_environment_unittests",
diff --git a/testing/buildbot/tryserver.blink.json b/testing/buildbot/tryserver.blink.json
index fe4d275..ce5481e 100644
--- a/testing/buildbot/tryserver.blink.json
+++ b/testing/buildbot/tryserver.blink.json
@@ -13,7 +13,6 @@
       "browser_tests",
       "cacheinvalidation_unittests",
       "chromedriver_unittests",
-      "chromeos_unittests",
       "components_browsertests",
       "components_unittests",
       "content_browsertests",
@@ -49,7 +48,6 @@
       "sql_unittests",
       "sync_unit_tests",
       "ui_base_unittests",
-      "ui_chromeos_unittests",
       "ui_touch_selection_unittests",
       "unit_tests",
       "url_unittests",
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
index 6d3c6d4..f5a7f98 100644
--- a/testing/buildbot/tryserver.chromium.linux.json
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -13,7 +13,46 @@
   },
   "linux_chromium_gn_chromeos_dbg": {
     "additional_compile_targets": [
-      "net_unittests"
+      "accessibility_unittests",
+      "app_list_unittests",
+      "aura_unittests",
+      "browser_tests",
+      "cacheinvalidation_unittests",
+      "chromedriver_unittests",
+      "chromeos_unittests",
+      "content_unittests",
+      "crypto_unittests",
+      "dbus_unittests",
+      "device_unittests",
+      "display_unittests",
+      "events_unittests",
+      "extensions_browsertests",
+      "extensions_unittests",
+      "gcm_unit_tests",
+      "gfx_unittests",
+      "gn_unittests",
+      "google_apis_unittests",
+      "gpu_unittests",
+      "interactive_ui_tests",
+      "ipc_tests",
+      "jingle_unittests",
+      "mandoline:all",
+      "media_unittests",
+      "net_unittests",
+      "ppapi_unittests",
+      "printing_unittests",
+      "remoting_unittests",
+      "sandbox_linux_unittests",
+      "skia_unittests",
+      "sql_unittests",
+      "sync_unit_tests",
+      "ui_base_unittests",
+      "ui_chromeos_unittests",
+      "ui_touch_selection_unittests",
+      "unit_tests",
+      "url_unittests",
+      "views_unittests",
+      "wm_unittests"
     ],
     "gtest_tests": [
       {
@@ -46,16 +85,12 @@
       "gn_unittests",
       "google_apis_unittests",
       "gpu_unittests",
+      "html_viewer_unittests",
       "interactive_ui_tests",
       "ipc_tests",
       "jingle_unittests",
+      "mandoline:all",
       "media_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "net_unittests",
       "ppapi_unittests",
       "printing_unittests",
@@ -69,6 +104,7 @@
       "ui_touch_selection_unittests",
       "unit_tests",
       "url_unittests",
+      "view_manager_service_unittests",
       "views_unittests",
       "wm_unittests"
     ],
@@ -108,13 +144,8 @@
       "ipc_mojo_unittests",
       "ipc_tests",
       "jingle_unittests",
+      "mandoline:all",
       "media_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "net_unittests",
       "ppapi_unittests",
       "printing_unittests",
@@ -163,17 +194,13 @@
       "gn_unittests",
       "google_apis_unittests",
       "gpu_unittests",
+      "html_viewer_unittests",
       "interactive_ui_tests",
       "ipc_mojo_unittests",
       "ipc_tests",
       "jingle_unittests",
+      "mandoline:all",
       "media_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "nacl_loader_unittests",
       "net_unittests",
       "ppapi_unittests",
@@ -188,6 +215,7 @@
       "ui_touch_selection_unittests",
       "unit_tests",
       "url_unittests",
+      "view_manager_service_unittests",
       "views_unittests",
       "wm_unittests"
     ],
diff --git a/testing/buildbot/tryserver.chromium.win.json b/testing/buildbot/tryserver.chromium.win.json
index 6710973..362c5e3 100644
--- a/testing/buildbot/tryserver.chromium.win.json
+++ b/testing/buildbot/tryserver.chromium.win.json
@@ -32,14 +32,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -94,14 +89,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -156,14 +146,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
@@ -218,14 +203,9 @@
       "ipc_tests",
       "jingle_unittests",
       "keyboard_unittests",
+      "mandoline:all",
       "media_unittests",
       "message_center_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
       "sbox_integration_tests",
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt
index c9ecb29..dbe2aee 100644
--- a/testing/chromoting/browser_test_commands_linux.txt
+++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -1,18 +1,18 @@
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_CancelShare --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_VerifyAccessCodeNonReusable --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Cancel_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Update_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Invalid_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123457 --override-user-data-dir=/tmp/chromoting_test_profile
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=FullscreenBrowserTest.MANUAL_Me2Me_Bump_Scroll --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_CancelShare --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_VerifyAccessCodeNonReusable --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Cancel_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Update_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Invalid_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123457 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=FullscreenBrowserTest.MANUAL_Me2Me_Bump_Scroll --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --test-launcher-print-test-stdio=always
 cd ../../remoting/internal/config && /usr/bin/python ./is_valid_json.py
\ No newline at end of file
diff --git a/testing/chromoting/browser_tests_launcher.py b/testing/chromoting/browser_tests_launcher.py
index 2fceb7c..1c9652f 100644
--- a/testing/chromoting/browser_tests_launcher.py
+++ b/testing/chromoting/browser_tests_launcher.py
@@ -13,6 +13,8 @@
 import socket
 import subprocess
 
+import psutil
+
 BROWSER_TEST_ID = 'browser_tests'
 PROD_DIR_ID = '#PROD_DIR#'
 HOST_HASH_VALUE = hashlib.md5(socket.gethostname()).hexdigest()
@@ -162,6 +164,15 @@
     shutil.copyfile(manifest_file_src, manifest_file_dest)
 
 
+def PrintRunningProcesses():
+  processes = psutil.get_process_list()
+  processes = sorted(processes, key=lambda process: process.name)
+
+  print 'List of running processes:\n'
+  for process in processes:
+    print process.name
+
+
 def main(args):
 
   InitialiseTestMachineForLinux(args.cfg_file)
@@ -182,6 +193,9 @@
         # Host restart failed. Don't run any more tests.
         raise Exception('Host restart failed.')
 
+      # Print list of currently running processes.
+      PrintRunningProcesses()
+
   # All tests completed. Include host-logs in the test results.
   host_log_contents = ''
   # There should be only 1 log file, as we delete logs on test completion.
diff --git a/testing/commit_queue/config.json b/testing/commit_queue/config.json
index aefd3c7..3338304 100644
--- a/testing/commit_queue/config.json
+++ b/testing/commit_queue/config.json
@@ -30,15 +30,6 @@
                 "trybots": {
                     "launched": {
                         "tryserver.chromium.linux": {
-                            "android_amp_rel_tests_recipe": [
-                                "defaulttests"
-                            ],
-                            "linux_arm_compile": [
-                                "defaulttests"
-                            ],
-                            "linux_chromium_asan_rel_ng": [
-                                "defaulttests"
-                            ]
                         },
                         "tryserver.chromium.mac": {
                             "mac_chromium_gn_rel": [
@@ -60,7 +51,14 @@
                 "percentage": 1.0,
                 "trybots": {
                     "launched": {
-                        "tryserver.chromium.linux": {},
+                        "tryserver.chromium.linux": {
+                            "android_amp_rel_tests_recipe": [
+                                "defaulttests"
+                            ],
+                            "linux_arm_compile": [
+                                "defaulttests"
+                            ]
+                        },
                         "tryserver.chromium.mac": {}
                     }
                 }
@@ -118,7 +116,7 @@
                     "linux_android_rel_ng": [
                         "defaulttests"
                     ],
-                    "linux_chromium_asan_rel": [
+                    "linux_chromium_asan_rel_ng": [
                         "defaulttests"
                     ],
                     "linux_chromium_chromeos_compile_dbg_ng": [
diff --git a/testing/scripts/telemetry_perf_unittests.py b/testing/scripts/telemetry_perf_unittests.py
index 42eb656..06e0181 100755
--- a/testing/scripts/telemetry_perf_unittests.py
+++ b/testing/scripts/telemetry_perf_unittests.py
@@ -16,16 +16,20 @@
   if args.filter_file:
     filter_tests = json.load(args.filter_file)
 
+  test_args = ['--retry-limit', '3']
+  if 'android' == args.properties.get('target_platform'):
+    test_args += ['--browser', 'android-chrome-shell', '--device', 'android']
+  else:
+    test_args += ['--browser', args.build_config_fs.lower()]
+
   with common.temporary_file() as tempfile_path:
+    test_args += ['--write-full-results-to', tempfile_path]
     rc = common.run_runtest(args, [
         '--annotate', 'gtest',
         '--test-type', 'telemetry_perf_unittests',
         '--run-python-script',
-        os.path.join(common.SRC_DIR, 'tools', 'perf', 'run_tests'),
-        '--browser', args.build_config_fs.lower(),
-        '--retry-limit', '3',
-        '--write-full-results-to', tempfile_path,
-    ] + filter_tests)
+        os.path.join(common.SRC_DIR, 'tools', 'perf', 'run_tests')
+    ] + test_args + filter_tests)
 
     with open(tempfile_path) as f:
       results = json.load(f)
@@ -43,7 +47,10 @@
 
 
 def main_compile_targets(args):
-  json.dump(['chrome'], args.output)
+  if 'android' == args.properties.get('target_platform'):
+    json.dump(['chrome_shell_apk'], args.output)
+  else:
+    json.dump(['chrome'], args.output)
 
 
 if __name__ == '__main__':
diff --git a/third_party/libevent/README.chromium b/third_party/libevent/README.chromium
index a3e5c6e..939a353 100644
--- a/third_party/libevent/README.chromium
+++ b/third_party/libevent/README.chromium
@@ -24,3 +24,5 @@
    nacl_nonsfi/random.c is also added to provide the random() function,
    which is missing in the newlib-based PNaCl toolchain.
 8) Apply https://github.com/libevent/libevent/commit/ea6b1df
+9) Stub out signal.c for nacl_helper_nonsfi. socketpair() will be prohibited
+   by sandbox in nacl_helper_nonsfi.
diff --git a/third_party/libevent/libevent_nacl_nonsfi.gyp b/third_party/libevent/libevent_nacl_nonsfi.gyp
index 37a78ad..2999ceb 100644
--- a/third_party/libevent/libevent_nacl_nonsfi.gyp
+++ b/third_party/libevent/libevent_nacl_nonsfi.gyp
@@ -19,11 +19,11 @@
             'evutil.c',
             'log.c',
             'poll.c',
-            'signal.c',
             'strlcpy.c',
             'nacl_nonsfi/config.h',
             'nacl_nonsfi/event-config.h',
             'nacl_nonsfi/random.c',
+            'nacl_nonsfi/signal_stub.c',
           ],
           'defines': [
             'HAVE_CONFIG_H',
diff --git a/third_party/libevent/nacl_nonsfi/signal_stub.c b/third_party/libevent/nacl_nonsfi/signal_stub.c
new file mode 100644
index 0000000..8049030
--- /dev/null
+++ b/third_party/libevent/nacl_nonsfi/signal_stub.c
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*
+ * In nacl_helper_nonsfi, socketpair() is unavailable. In libevent, it is used
+ * to notify of a signal handler invocation, which is unused in
+ * nacl_helper_nonsfi. Unfortunately, there is no macro to disable the feature,
+ * so we stub out the signal module entirely.
+ */
+
+
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+/* config.h must be included before any other libevent header is included. */
+#include "config.h"
+
+#include "third_party/libevent/event-internal.h"
+#include "third_party/libevent/event.h"
+#include "third_party/libevent/evsignal.h"
+
+
+struct event_base *evsignal_base = 0;
+
+int evsignal_init(struct event_base *base) {
+  /* Do nothing, and return success. */
+  return 0;
+}
+
+void evsignal_process(struct event_base *base) {
+}
+
+int evsignal_add(struct event *event) {
+  /* Do nothing, and return an error. */
+  return -1;
+}
+
+int evsignal_del(struct event *event) {
+  /* Do nothing, and return an error. */
+  return -1;
+}
+
+void evsignal_dealloc(struct event_base *base) {
+}
diff --git a/third_party/libxml/BUILD.gn b/third_party/libxml/BUILD.gn
index 299a110..7fb6678 100644
--- a/third_party/libxml/BUILD.gn
+++ b/third_party/libxml/BUILD.gn
@@ -65,8 +65,6 @@
     "src/include/libxml/globals.h",
     "src/include/libxml/hash.h",
     "src/include/libxml/list.h",
-    "src/include/libxml/nanoftp.h",
-    "src/include/libxml/nanohttp.h",
     "src/include/libxml/parser.h",
     "src/include/libxml/parserInternals.h",
     "src/include/libxml/pattern.h",
@@ -101,8 +99,6 @@
     "src/legacy.c",
     "src/libxml.h",
     "src/list.c",
-    "src/nanoftp.c",
-    "src/nanohttp.c",
     "src/parser.c",
     "src/parserInternals.c",
     "src/pattern.c",
diff --git a/third_party/libxml/OWNERS b/third_party/libxml/OWNERS
new file mode 100644
index 0000000..eb6ce62
--- /dev/null
+++ b/third_party/libxml/OWNERS
@@ -0,0 +1,4 @@
+# There's no real owners here. If you're familiar with the code please send
+# a CL to add yourself here.
+cpu@chromium.org
+scottmg@chromium.org
diff --git a/third_party/libxml/README.chromium b/third_party/libxml/README.chromium
index f12d267..1f3162f 100644
--- a/third_party/libxml/README.chromium
+++ b/third_party/libxml/README.chromium
@@ -22,21 +22,23 @@
 - Add a fix for handling of unknown namespaces, commit upstream is pending.
 - Add fixes for ending the parse properly if a SAX callback calls xmlStopParser(), commit upstream is pending.
 - Add fix for entities, commit upstream is http://git.gnome.org/browse/libxml2/commit/?id=5bd3c061823a8499b27422aee04ea20aae24f03e
-- Import UTF-8 fix from upstream: http://git.gnome.org/browse/libxml2/commit/?id=0795348aeb86648723bc391e4d02e20631c10bca 
+- Import UTF-8 fix from upstream: http://git.gnome.org/browse/libxml2/commit/?id=0795348aeb86648723bc391e4d02e20631c10bca
 - Import XPath fix http://git.gnome.org/browse/libxml2/commit/xpath.c?id=2ddecc23862bab1a9a9e51e097aefc92ec305e28
 - Merge clang warning fix http://git.gnome.org/browse/libxml2/commit/?id=aae48e64dfbf2b46b157a4c1857e30645116388f
 - Add a fix for proper escaping of xpointer expressions, commit upstream is pending.
 - Add helper classes in chromium/libxml_utils.cc and chromium/include/libxml/libxml_utils.h.
 - Add a tweak to limit problems caused by excessive strings and buffers.
 - Change the xmlNs struct a little bit, so it looks like it has no children
-- Prevent snprintf from being defined as _snprintf on VS 2015.
-if treated as a generic xmlNode object.
+  if treated as a generic xmlNode object.
 - Fix pretty harmless use-after-free in generate-id function.
 - Merge a clang warning fix http://git.gnome.org/browse/libxml2/commit/?id=713434d2309da469d64b35e163ea6556dadccada
 - Import attribute normalization fix http://git.gnome.org/browse/libxml2/commit/?id=6a36fbe3b3e001a8a840b5c1fdd81cefc9947f0d
 - Merge a redundant comparison fix http://git.gnome.org/browse/libxml2/commit/?id=2af19f985b911b6dc6ada478ba8d201d2ddc9309
 - Merge a redundant comparisons fix https://git.gnome.org/browse/libxml2/commit/?id=eea38159be421dbafbee38f40e239f91734bc713
 - Merge XML_PARSER_EOF checks https://git.gnome.org/browse/libxml2/commit/?id=48b4cdde3483e054af8ea02e0cd7ee467b0e9a50 and https://git.gnome.org/browse/libxml2/commit/?id=e50ba8164eee06461c73cd8abb9b46aa0be81869
+- Prevent snprintf from being defined as _snprintf on VS 2015.
+- Make ucrt of Win10 SDK not define POSIX error codes.
+- Delete/disable nanoftp and nanohttp.
 
 To import a new snapshot of libxml:
 
diff --git a/third_party/libxml/libxml.gyp b/third_party/libxml/libxml.gyp
index 1decbe9..51e45db 100644
--- a/third_party/libxml/libxml.gyp
+++ b/third_party/libxml/libxml.gyp
@@ -96,8 +96,6 @@
             'src/include/libxml/HTMLparser.h',
             'src/include/libxml/HTMLtree.h',
             'src/include/libxml/list.h',
-            'src/include/libxml/nanoftp.h',
-            'src/include/libxml/nanohttp.h',
             'src/include/libxml/parser.h',
             'src/include/libxml/parserInternals.h',
             'src/include/libxml/pattern.h',
@@ -149,8 +147,6 @@
             'src/legacy.c',
             'src/libxml.h',
             'src/list.c',
-            'src/nanoftp.c',
-            'src/nanohttp.c',
             'src/parser.c',
             'src/parserInternals.c',
             'src/pattern.c',
diff --git a/third_party/libxml/patches/win32-no-posix-error-codes b/third_party/libxml/patches/win32-no-posix-error-codes
new file mode 100644
index 0000000..38be7f7
--- /dev/null
+++ b/third_party/libxml/patches/win32-no-posix-error-codes
@@ -0,0 +1,14 @@
+diff --git a/third_party/libxml/src/libxml.h b/third_party/libxml/src/libxml.h
+index 1656ac2..f8a368c 100644
+--- a/third_party/libxml/src/libxml.h
++++ b/third_party/libxml/src/libxml.h
+@@ -17,6 +17,9 @@
+ #define _FILE_OFFSET_BITS 64
+ #endif
+ #endif
++#ifndef _CRT_NO_POSIX_ERROR_CODES
++#define _CRT_NO_POSIX_ERROR_CODES
++#endif
+ 
+ #if defined(macintosh)
+ #include "config-mac.h"
diff --git a/third_party/libxml/src/include/libxml/nanoftp.h b/third_party/libxml/src/include/libxml/nanoftp.h
deleted file mode 100644
index e3c28a0..0000000
--- a/third_party/libxml/src/include/libxml/nanoftp.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Summary: minimal FTP implementation
- * Description: minimal FTP implementation allowing to fetch resources
- *              like external subset.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
- 
-#ifndef __NANO_FTP_H__
-#define __NANO_FTP_H__
-
-#include <libxml/xmlversion.h>
-
-#ifdef LIBXML_FTP_ENABLED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * ftpListCallback: 
- * @userData:  user provided data for the callback
- * @filename:  the file name (including "->" when links are shown)
- * @attrib:  the attribute string
- * @owner:  the owner string
- * @group:  the group string
- * @size:  the file size
- * @links:  the link count
- * @year:  the year
- * @month:  the month
- * @day:  the day
- * @hour:  the hour
- * @minute:  the minute
- *
- * A callback for the xmlNanoFTPList command.
- * Note that only one of year and day:minute are specified.
- */
-typedef void (*ftpListCallback) (void *userData,
-	                         const char *filename, const char *attrib,
-	                         const char *owner, const char *group,
-				 unsigned long size, int links, int year,
-				 const char *month, int day, int hour,
-				 int minute);
-/**
- * ftpDataCallback: 
- * @userData: the user provided context
- * @data: the data received
- * @len: its size in bytes
- *
- * A callback for the xmlNanoFTPGet command.
- */
-typedef void (*ftpDataCallback) (void *userData,
-				 const char *data,
-				 int len);
-
-/*
- * Init
- */
-XMLPUBFUN void XMLCALL
-	xmlNanoFTPInit		(void);
-XMLPUBFUN void XMLCALL	
-	xmlNanoFTPCleanup	(void);
-
-/*
- * Creating/freeing contexts.
- */
-XMLPUBFUN void * XMLCALL	
-	xmlNanoFTPNewCtxt	(const char *URL);
-XMLPUBFUN void XMLCALL	
-	xmlNanoFTPFreeCtxt	(void * ctx);
-XMLPUBFUN void * XMLCALL 	
-	xmlNanoFTPConnectTo	(const char *server,
-				 int port);
-/*
- * Opening/closing session connections.
- */
-XMLPUBFUN void * XMLCALL 	
-	xmlNanoFTPOpen		(const char *URL);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPConnect	(void *ctx);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPClose		(void *ctx);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPQuit		(void *ctx);
-XMLPUBFUN void XMLCALL	
-	xmlNanoFTPScanProxy	(const char *URL);
-XMLPUBFUN void XMLCALL	
-	xmlNanoFTPProxy		(const char *host,
-				 int port,
-				 const char *user,
-				 const char *passwd,
-				 int type);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPUpdateURL	(void *ctx,
-				 const char *URL);
-
-/*
- * Rather internal commands.
- */
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPGetResponse	(void *ctx);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPCheckResponse	(void *ctx);
-
-/*
- * CD/DIR/GET handlers.
- */
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPCwd		(void *ctx,
-				 const char *directory);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPDele		(void *ctx,
-				 const char *file);
-
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPGetConnection	(void *ctx);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPCloseConnection(void *ctx);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPList		(void *ctx,
-				 ftpListCallback callback,
-				 void *userData,
-				 const char *filename);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPGetSocket	(void *ctx,
-				 const char *filename);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPGet		(void *ctx,
-				 ftpDataCallback callback,
-				 void *userData,
-				 const char *filename);
-XMLPUBFUN int XMLCALL	
-	xmlNanoFTPRead		(void *ctx,
-				 void *dest,
-				 int len);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* LIBXML_FTP_ENABLED */
-#endif /* __NANO_FTP_H__ */
diff --git a/third_party/libxml/src/include/libxml/nanohttp.h b/third_party/libxml/src/include/libxml/nanohttp.h
deleted file mode 100644
index 1d8ac24..0000000
--- a/third_party/libxml/src/include/libxml/nanohttp.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Summary: minimal HTTP implementation
- * Description: minimal HTTP implementation allowing to fetch resources
- *              like external subset.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
- 
-#ifndef __NANO_HTTP_H__
-#define __NANO_HTTP_H__
-
-#include <libxml/xmlversion.h>
-
-#ifdef LIBXML_HTTP_ENABLED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-XMLPUBFUN void XMLCALL
-	xmlNanoHTTPInit		(void);
-XMLPUBFUN void XMLCALL	
-	xmlNanoHTTPCleanup	(void);
-XMLPUBFUN void XMLCALL	
-	xmlNanoHTTPScanProxy	(const char *URL);
-XMLPUBFUN int XMLCALL	
-	xmlNanoHTTPFetch	(const char *URL,
-				 const char *filename,
-				 char **contentType);
-XMLPUBFUN void * XMLCALL	
-	xmlNanoHTTPMethod	(const char *URL,
-				 const char *method,
-				 const char *input,
-				 char **contentType,
-				 const char *headers,
-				 int   ilen);
-XMLPUBFUN void * XMLCALL	
-	xmlNanoHTTPMethodRedir	(const char *URL,
-				 const char *method,
-				 const char *input,
-				 char **contentType,
-				 char **redir,
-				 const char *headers,
-				 int   ilen);
-XMLPUBFUN void * XMLCALL	
-	xmlNanoHTTPOpen		(const char *URL,
-				 char **contentType);
-XMLPUBFUN void * XMLCALL	
-	xmlNanoHTTPOpenRedir	(const char *URL,
-				 char **contentType,
-				 char **redir);
-XMLPUBFUN int XMLCALL	
-	xmlNanoHTTPReturnCode	(void *ctx);
-XMLPUBFUN const char * XMLCALL 
-	xmlNanoHTTPAuthHeader	(void *ctx);
-XMLPUBFUN const char * XMLCALL
-	xmlNanoHTTPRedir	(void *ctx);
-XMLPUBFUN int XMLCALL
-	xmlNanoHTTPContentLength( void * ctx );
-XMLPUBFUN const char * XMLCALL
-	xmlNanoHTTPEncoding	(void *ctx);
-XMLPUBFUN const char * XMLCALL
-	xmlNanoHTTPMimeType	(void *ctx);
-XMLPUBFUN int XMLCALL	
-	xmlNanoHTTPRead		(void *ctx,
-				 void *dest,
-				 int len);
-#ifdef LIBXML_OUTPUT_ENABLED
-XMLPUBFUN int XMLCALL	
-	xmlNanoHTTPSave		(void *ctxt,
-				 const char *filename);
-#endif /* LIBXML_OUTPUT_ENABLED */
-XMLPUBFUN void XMLCALL	
-	xmlNanoHTTPClose	(void *ctx);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBXML_HTTP_ENABLED */
-#endif /* __NANO_HTTP_H__ */
diff --git a/third_party/libxml/src/libxml.h b/third_party/libxml/src/libxml.h
index 1656ac2..f8a368c 100644
--- a/third_party/libxml/src/libxml.h
+++ b/third_party/libxml/src/libxml.h
@@ -17,6 +17,9 @@
 #define _FILE_OFFSET_BITS 64
 #endif
 #endif
+#ifndef _CRT_NO_POSIX_ERROR_CODES
+#define _CRT_NO_POSIX_ERROR_CODES
+#endif
 
 #if defined(macintosh)
 #include "config-mac.h"
diff --git a/third_party/libxml/src/nanoftp.c b/third_party/libxml/src/nanoftp.c
deleted file mode 100644
index a54b85b..0000000
--- a/third_party/libxml/src/nanoftp.c
+++ /dev/null
@@ -1,2111 +0,0 @@
-/*
- * nanoftp.c: basic FTP client support
- *
- *  Reference: RFC 959
- */
-
-#ifdef TESTING
-#define STANDALONE
-#define HAVE_STDLIB_H
-#define HAVE_UNISTD_H
-#define HAVE_SYS_SOCKET_H
-#define HAVE_NETINET_IN_H
-#define HAVE_NETDB_H
-#define HAVE_SYS_TIME_H
-#else /* TESTING */
-#define NEED_SOCKETS
-#endif /* TESTING */
-
-#define IN_LIBXML
-#include "libxml.h"
-
-#ifdef LIBXML_FTP_ENABLED
-#include <string.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h> 
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/xmlerror.h>
-#include <libxml/uri.h>
-#include <libxml/nanoftp.h>
-#include <libxml/globals.h>
-
-/* #define DEBUG_FTP 1  */
-#ifdef STANDALONE
-#ifndef DEBUG_FTP
-#define DEBUG_FTP 1
-#endif
-#endif
-
-
-#if defined(__MINGW32__) || defined(_WIN32_WCE)
-#define _WINSOCKAPI_
-#include <wsockcompat.h>
-#include <winsock2.h>
-#undef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-
-/**
- * A couple portability macros
- */
-#ifndef _WINSOCKAPI_
-#if !defined(__BEOS__) || defined(__HAIKU__)
-#define closesocket(s) close(s)
-#endif
-#define SOCKET int
-#endif
-
-#ifdef __BEOS__
-#ifndef PF_INET
-#define PF_INET AF_INET
-#endif
-#endif
-
-#ifdef _AIX
-#ifdef HAVE_BROKEN_SS_FAMILY
-#define ss_family __ss_family
-#endif
-#endif
-
-#ifndef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-
-#define FTP_COMMAND_OK		200
-#define FTP_SYNTAX_ERROR	500
-#define FTP_GET_PASSWD		331
-#define FTP_BUF_SIZE		1024
-
-#define XML_NANO_MAX_URLBUF	4096
-
-typedef struct xmlNanoFTPCtxt {
-    char *protocol;	/* the protocol name */
-    char *hostname;	/* the host name */
-    int port;		/* the port */
-    char *path;		/* the path within the URL */
-    char *user;		/* user string */
-    char *passwd;	/* passwd string */
-#ifdef SUPPORT_IP6
-    struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
-#else
-    struct sockaddr_in ftpAddr; /* the socket address struct */
-#endif
-    int passive;	/* currently we support only passive !!! */
-    SOCKET controlFd;	/* the file descriptor for the control socket */
-    SOCKET dataFd;	/* the file descriptor for the data socket */
-    int state;		/* WRITE / READ / CLOSED */
-    int returnValue;	/* the protocol return value */
-    /* buffer for data received from the control connection */
-    char controlBuf[FTP_BUF_SIZE + 1];
-    int controlBufIndex;
-    int controlBufUsed;
-    int controlBufAnswer;
-} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
-
-static int initialized = 0;
-static char *proxy = NULL;	/* the proxy name if any */
-static int proxyPort = 0;	/* the proxy port if any */
-static char *proxyUser = NULL;	/* user for proxy authentication */
-static char *proxyPasswd = NULL;/* passwd for proxy authentication */
-static int proxyType = 0;	/* uses TYPE or a@b ? */
-
-#ifdef SUPPORT_IP6
-static
-int have_ipv6(void) {
-    int s;
-
-    s = socket (AF_INET6, SOCK_STREAM, 0);
-    if (s != -1) {
-	close (s);
-	return (1);
-    }
-    return (0);
-}
-#endif
-
-/**
- * xmlFTPErrMemory:
- * @extra:  extra informations
- *
- * Handle an out of memory condition
- */
-static void
-xmlFTPErrMemory(const char *extra)
-{
-    __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
-}
-
-/**
- * xmlNanoFTPInit:
- *
- * Initialize the FTP protocol layer.
- * Currently it just checks for proxy informations,
- * and get the hostname
- */
-
-void
-xmlNanoFTPInit(void) {
-    const char *env;
-#ifdef _WINSOCKAPI_
-    WSADATA wsaData;    
-#endif
-
-    if (initialized)
-	return;
-
-#ifdef _WINSOCKAPI_
-    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
-	return;
-#endif
-
-    proxyPort = 21;
-    env = getenv("no_proxy");
-    if (env && ((env[0] == '*' ) && (env[1] == 0)))
-	return;
-    env = getenv("ftp_proxy");
-    if (env != NULL) {
-	xmlNanoFTPScanProxy(env);
-    } else {
-	env = getenv("FTP_PROXY");
-	if (env != NULL) {
-	    xmlNanoFTPScanProxy(env);
-	}
-    }
-    env = getenv("ftp_proxy_user");
-    if (env != NULL) {
-	proxyUser = xmlMemStrdup(env);
-    }
-    env = getenv("ftp_proxy_password");
-    if (env != NULL) {
-	proxyPasswd = xmlMemStrdup(env);
-    }
-    initialized = 1;
-}
-
-/**
- * xmlNanoFTPCleanup:
- *
- * Cleanup the FTP protocol layer. This cleanup proxy informations.
- */
-
-void
-xmlNanoFTPCleanup(void) {
-    if (proxy != NULL) {
-	xmlFree(proxy);
-	proxy = NULL;
-    }
-    if (proxyUser != NULL) {
-	xmlFree(proxyUser);
-	proxyUser = NULL;
-    }
-    if (proxyPasswd != NULL) {
-	xmlFree(proxyPasswd);
-	proxyPasswd = NULL;
-    }
-#ifdef _WINSOCKAPI_
-    if (initialized)
-	WSACleanup();
-#endif
-    initialized = 0;
-}
-
-/**
- * xmlNanoFTPProxy:
- * @host:  the proxy host name
- * @port:  the proxy port
- * @user:  the proxy user name
- * @passwd:  the proxy password
- * @type:  the type of proxy 1 for using SITE, 2 for USER a@b
- *
- * Setup the FTP proxy informations.
- * This can also be done by using ftp_proxy ftp_proxy_user and
- * ftp_proxy_password environment variables.
- */
-
-void
-xmlNanoFTPProxy(const char *host, int port, const char *user,
-	        const char *passwd, int type) {
-    if (proxy != NULL) {
-	xmlFree(proxy);
-	proxy = NULL;
-    }
-    if (proxyUser != NULL) {
-	xmlFree(proxyUser);
-	proxyUser = NULL;
-    }
-    if (proxyPasswd != NULL) {
-	xmlFree(proxyPasswd);
-	proxyPasswd = NULL;
-    }
-    if (host)
-	proxy = xmlMemStrdup(host);
-    if (user)
-	proxyUser = xmlMemStrdup(user);
-    if (passwd)
-	proxyPasswd = xmlMemStrdup(passwd);
-    proxyPort = port;
-    proxyType = type;
-}
-
-/**
- * xmlNanoFTPScanURL:
- * @ctx:  an FTP context
- * @URL:  The URL used to initialize the context
- *
- * (Re)Initialize an FTP context by parsing the URL and finding
- * the protocol host port and path it indicates.
- */
-
-static void
-xmlNanoFTPScanURL(void *ctx, const char *URL) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    xmlURIPtr uri;
-
-    /*
-     * Clear any existing data from the context
-     */
-    if (ctxt->protocol != NULL) { 
-        xmlFree(ctxt->protocol);
-	ctxt->protocol = NULL;
-    }
-    if (ctxt->hostname != NULL) { 
-        xmlFree(ctxt->hostname);
-	ctxt->hostname = NULL;
-    }
-    if (ctxt->path != NULL) { 
-        xmlFree(ctxt->path);
-	ctxt->path = NULL;
-    }
-    if (URL == NULL) return;
-
-    uri = xmlParseURIRaw(URL, 1);
-    if (uri == NULL)
-	return;
-
-    if ((uri->scheme == NULL) || (uri->server == NULL)) {
-	xmlFreeURI(uri);
-	return;
-    }
-    
-    ctxt->protocol = xmlMemStrdup(uri->scheme);
-    ctxt->hostname = xmlMemStrdup(uri->server);
-    if (uri->path != NULL)
-	ctxt->path = xmlMemStrdup(uri->path);
-    else
-	ctxt->path = xmlMemStrdup("/");
-    if (uri->port != 0)
-	ctxt->port = uri->port;
-
-    if (uri->user != NULL) {
-	char *cptr;
-	if ((cptr=strchr(uri->user, ':')) == NULL)
-	    ctxt->user = xmlMemStrdup(uri->user);
-	else {
-	    ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user,
-			    (cptr - uri->user));
-	    ctxt->passwd = xmlMemStrdup(cptr+1);
-	}
-    }
-
-    xmlFreeURI(uri);
-
-}
-
-/**
- * xmlNanoFTPUpdateURL:
- * @ctx:  an FTP context
- * @URL:  The URL used to update the context
- *
- * Update an FTP context by parsing the URL and finding
- * new path it indicates. If there is an error in the 
- * protocol, hostname, port or other information, the
- * error is raised. It indicates a new connection has to
- * be established.
- *
- * Returns 0 if Ok, -1 in case of error (other host).
- */
-
-int
-xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    xmlURIPtr uri;
-
-    if (URL == NULL)
-	return(-1);
-    if (ctxt == NULL)
-	return(-1);
-    if (ctxt->protocol == NULL)
-	return(-1);
-    if (ctxt->hostname == NULL)
-	return(-1);
-
-    uri = xmlParseURIRaw(URL, 1);
-    if (uri == NULL)
-	return(-1);
-
-    if ((uri->scheme == NULL) || (uri->server == NULL)) {
-	xmlFreeURI(uri);
-	return(-1);
-    }
-    if ((strcmp(ctxt->protocol, uri->scheme)) ||
-	(strcmp(ctxt->hostname, uri->server)) ||
-	((uri->port != 0) && (ctxt->port != uri->port))) {
-	xmlFreeURI(uri);
-	return(-1);
-    }
-
-    if (uri->port != 0)
-	ctxt->port = uri->port;
-
-    if (ctxt->path != NULL) {
-	xmlFree(ctxt->path);
-	ctxt->path = NULL;
-    }
-
-    if (uri->path == NULL) 
-        ctxt->path = xmlMemStrdup("/");
-    else
-	ctxt->path = xmlMemStrdup(uri->path);
-
-    xmlFreeURI(uri);
-
-    return(0);
-}
-
-/**
- * xmlNanoFTPScanProxy:
- * @URL:  The proxy URL used to initialize the proxy context
- *
- * (Re)Initialize the FTP Proxy context by parsing the URL and finding
- * the protocol host port it indicates.
- * Should be like ftp://myproxy/ or ftp://myproxy:3128/
- * A NULL URL cleans up proxy informations.
- */
-
-void
-xmlNanoFTPScanProxy(const char *URL) {
-    xmlURIPtr uri;
-
-    if (proxy != NULL) { 
-        xmlFree(proxy);
-	proxy = NULL;
-    }
-    proxyPort = 0;
-
-#ifdef DEBUG_FTP
-    if (URL == NULL)
-	xmlGenericError(xmlGenericErrorContext,
-		"Removing FTP proxy info\n");
-    else
-	xmlGenericError(xmlGenericErrorContext,
-		"Using FTP proxy %s\n", URL);
-#endif
-    if (URL == NULL) return;
-
-    uri = xmlParseURIRaw(URL, 1);
-    if ((uri == NULL) || (uri->scheme == NULL) ||
-	(strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) {
-	__xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n");
-	if (uri != NULL)
-	    xmlFreeURI(uri);
-	return;
-    }
-    
-    proxy = xmlMemStrdup(uri->server);
-    if (uri->port != 0)
-	proxyPort = uri->port;
-
-    xmlFreeURI(uri);
-}
-
-/**
- * xmlNanoFTPNewCtxt:
- * @URL:  The URL used to initialize the context
- *
- * Allocate and initialize a new FTP context.
- *
- * Returns an FTP context or NULL in case of error.
- */
-
-void*
-xmlNanoFTPNewCtxt(const char *URL) {
-    xmlNanoFTPCtxtPtr ret;
-    char *unescaped;
-
-    ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
-    if (ret == NULL) {
-        xmlFTPErrMemory("allocating FTP context");
-        return(NULL);
-    }
-
-    memset(ret, 0, sizeof(xmlNanoFTPCtxt));
-    ret->port = 21;
-    ret->passive = 1;
-    ret->returnValue = 0;
-    ret->controlBufIndex = 0;
-    ret->controlBufUsed = 0;
-    ret->controlFd = -1;
-
-    unescaped = xmlURIUnescapeString(URL, 0, NULL);
-    if (unescaped != NULL) {
-	xmlNanoFTPScanURL(ret, unescaped);
-	xmlFree(unescaped);
-    } else if (URL != NULL)
-	xmlNanoFTPScanURL(ret, URL);
-
-    return(ret);
-}
-
-/**
- * xmlNanoFTPFreeCtxt:
- * @ctx:  an FTP context
- *
- * Frees the context after closing the connection.
- */
-
-void
-xmlNanoFTPFreeCtxt(void * ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    if (ctxt == NULL) return;
-    if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
-    if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
-    if (ctxt->path != NULL) xmlFree(ctxt->path);
-    ctxt->passive = 1;
-    if (ctxt->controlFd >= 0) closesocket(ctxt->controlFd);
-    ctxt->controlFd = -1;
-    ctxt->controlBufIndex = -1;
-    ctxt->controlBufUsed = -1;
-    xmlFree(ctxt);
-}
-
-/**
- * xmlNanoFTPParseResponse:
- * @buf:  the buffer containing the response
- * @len:  the buffer length
- * 
- * Parsing of the server answer, we just extract the code.
- *
- * returns 0 for errors
- *     +XXX for last line of response
- *     -XXX for response to be continued
- */
-static int
-xmlNanoFTPParseResponse(char *buf, int len) {
-    int val = 0;
-
-    if (len < 3) return(-1);
-    if ((*buf >= '0') && (*buf <= '9')) 
-        val = val * 10 + (*buf - '0');
-    else
-        return(0);
-    buf++;
-    if ((*buf >= '0') && (*buf <= '9')) 
-        val = val * 10 + (*buf - '0');
-    else
-        return(0);
-    buf++;
-    if ((*buf >= '0') && (*buf <= '9')) 
-        val = val * 10 + (*buf - '0');
-    else
-        return(0);
-    buf++;
-    if (*buf == '-') 
-        return(-val);
-    return(val);
-}
-
-/**
- * xmlNanoFTPGetMore:
- * @ctx:  an FTP context
- *
- * Read more information from the FTP control connection
- * Returns the number of bytes read, < 0 indicates an error
- */
-static int
-xmlNanoFTPGetMore(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    int len;
-    int size;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
-    if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
-#ifdef DEBUG_FTP
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNanoFTPGetMore : controlBufIndex = %d\n",
-		ctxt->controlBufIndex);
-#endif
-	return(-1);
-    }
-
-    if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
-#ifdef DEBUG_FTP
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNanoFTPGetMore : controlBufUsed = %d\n",
-		ctxt->controlBufUsed);
-#endif
-	return(-1);
-    }
-    if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
-#ifdef DEBUG_FTP
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
-	       ctxt->controlBufIndex, ctxt->controlBufUsed);
-#endif
-	return(-1);
-    }
-
-    /*
-     * First pack the control buffer
-     */
-    if (ctxt->controlBufIndex > 0) {
-	memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
-		ctxt->controlBufUsed - ctxt->controlBufIndex);
-	ctxt->controlBufUsed -= ctxt->controlBufIndex;
-	ctxt->controlBufIndex = 0;
-    }
-    size = FTP_BUF_SIZE - ctxt->controlBufUsed;
-    if (size == 0) {
-#ifdef DEBUG_FTP
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
-#endif
-	return(0);
-    }
-
-    /*
-     * Read the amount left on the control connection
-     */
-    if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
-		    size, 0)) < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
-	closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-        ctxt->controlFd = -1;
-        return(-1);
-    }
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext,
-	    "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
-	   ctxt->controlBufUsed, ctxt->controlBufUsed + len);
-#endif
-    ctxt->controlBufUsed += len;
-    ctxt->controlBuf[ctxt->controlBufUsed] = 0;
-
-    return(len);
-}
-
-/**
- * xmlNanoFTPReadResponse:
- * @ctx:  an FTP context
- *
- * Read the response from the FTP server after a command.
- * Returns the code number
- */
-static int
-xmlNanoFTPReadResponse(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char *ptr, *end;
-    int len;
-    int res = -1, cur = -1;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
-get_more:
-    /*
-     * Assumes everything up to controlBuf[controlBufIndex] has been read
-     * and analyzed.
-     */
-    len = xmlNanoFTPGetMore(ctx);
-    if (len < 0) {
-        return(-1);
-    }
-    if ((ctxt->controlBufUsed == 0) && (len == 0)) {
-        return(-1);
-    }
-    ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
-    end = &ctxt->controlBuf[ctxt->controlBufUsed];
-
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext,
-	    "\n<<<\n%s\n--\n", ptr);
-#endif
-    while (ptr < end) {
-        cur = xmlNanoFTPParseResponse(ptr, end - ptr);
-	if (cur > 0) {
-	    /*
-	     * Successfully scanned the control code, scratch
-	     * till the end of the line, but keep the index to be
-	     * able to analyze the result if needed.
-	     */
-	    res = cur;
-	    ptr += 3;
-	    ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
-	    while ((ptr < end) && (*ptr != '\n')) ptr++;
-	    if (*ptr == '\n') ptr++;
-	    if (*ptr == '\r') ptr++;
-	    break;
-	}
-	while ((ptr < end) && (*ptr != '\n')) ptr++;
-	if (ptr >= end) {
-	    ctxt->controlBufIndex = ctxt->controlBufUsed;
-	    goto get_more;
-	}
-	if (*ptr != '\r') ptr++;
-    }
-
-    if (res < 0) goto get_more;
-    ctxt->controlBufIndex = ptr - ctxt->controlBuf;
-#ifdef DEBUG_FTP
-    ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
-    xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
-#endif
-
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
-#endif
-    return(res / 100);
-}
-
-/**
- * xmlNanoFTPGetResponse:
- * @ctx:  an FTP context
- *
- * Get the response from the FTP server after a command.
- * Returns the code number
- */
-
-int
-xmlNanoFTPGetResponse(void *ctx) {
-    int res;
-
-    res = xmlNanoFTPReadResponse(ctx);
-
-    return(res);
-}
-
-/**
- * xmlNanoFTPCheckResponse:
- * @ctx:  an FTP context
- *
- * Check if there is a response from the FTP server after a command.
- * Returns the code number, or 0
- */
-
-int
-xmlNanoFTPCheckResponse(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    fd_set rfd;
-    struct timeval tv;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-    tv.tv_sec = 0;
-    tv.tv_usec = 0;
-    FD_ZERO(&rfd);
-    FD_SET(ctxt->controlFd, &rfd);
-    switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
-	case 0:
-	    return(0);
-	case -1:
-	    __xmlIOErr(XML_FROM_FTP, 0, "select");
-	    return(-1);
-			
-    }
-
-    return(xmlNanoFTPReadResponse(ctx));
-}
-
-/**
- * Send the user authentication
- */
-
-static int
-xmlNanoFTPSendUser(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[200];
-    int len;
-    int res;
-
-    if (ctxt->user == NULL)
-	snprintf(buf, sizeof(buf), "USER anonymous\r\n");
-    else
-	snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
-    buf[sizeof(buf) - 1] = 0;
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	return(res);
-    }
-    return(0);
-}
-
-/**
- * Send the password authentication
- */
-
-static int
-xmlNanoFTPSendPasswd(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[200];
-    int len;
-    int res;
-
-    if (ctxt->passwd == NULL)
-	snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
-    else
-	snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
-    buf[sizeof(buf) - 1] = 0;
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	return(res);
-    }
-    return(0);
-}
-
-/**
- * xmlNanoFTPQuit:
- * @ctx:  an FTP context
- *
- * Send a QUIT command to the server
- *
- * Returns -1 in case of error, 0 otherwise
- */
-
-
-int
-xmlNanoFTPQuit(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[200];
-    int len, res;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
-    snprintf(buf, sizeof(buf), "QUIT\r\n");
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	return(res);
-    }
-    return(0);
-}
-
-/**
- * xmlNanoFTPConnect:
- * @ctx:  an FTP context
- *
- * Tries to open a control connection
- *
- * Returns -1 in case of error, 0 otherwise
- */
-
-int
-xmlNanoFTPConnect(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    struct hostent *hp;
-    int port;
-    int res;
-    int addrlen = sizeof (struct sockaddr_in);
-
-    if (ctxt == NULL)
-	return(-1);
-    if (ctxt->hostname == NULL)
-	return(-1);
-
-    /*
-     * do the blocking DNS query.
-     */
-    if (proxy) {
-        port = proxyPort;
-    } else {
-	port = ctxt->port;
-    }
-    if (port == 0)
-	port = 21;
-
-    memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
-
-#ifdef SUPPORT_IP6
-    if (have_ipv6 ()) {
-	struct addrinfo hints, *tmp, *result;
-
-	result = NULL;
-	memset (&hints, 0, sizeof(hints));
-	hints.ai_socktype = SOCK_STREAM;
-
-	if (proxy) {
-	    if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
-		__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
-		return (-1);
-	    }
-	}
-	else
-	    if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
-		__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
-		return (-1);
-	    }
-
-	for (tmp = result; tmp; tmp = tmp->ai_next)
-	    if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
-		break;
-
-	if (!tmp) {
-	    if (result)
-		freeaddrinfo (result);
-	    __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
-	    return (-1);
-	}
-	if (tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
-	    return (-1);
-	}
-	if (tmp->ai_family == AF_INET6) {
-	    memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
-	    ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
-	    ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
-	}
-	else {
-	    memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
-	    ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
-	    ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
-	}
-	addrlen = tmp->ai_addrlen;
-	freeaddrinfo (result);
-    }
-    else
-#endif
-    {
-	if (proxy)
-	    hp = gethostbyname (proxy);
-	else
-	    hp = gethostbyname (ctxt->hostname);
-	if (hp == NULL) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
-	    return (-1);
-	}
-	if ((unsigned int) hp->h_length >
-	    sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
-	    return (-1);
-	}
-
-	/*
-	 * Prepare the socket
-	 */
-	((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
-	memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
-		hp->h_addr_list[0], hp->h_length);
-	((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = (u_short)htons ((unsigned short)port);
-	ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
-	addrlen = sizeof (struct sockaddr_in);
-    }
-
-    if (ctxt->controlFd < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "socket failed");
-        return(-1);
-    }
-
-    /*
-     * Do the connect.
-     */
-    if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
-	    addrlen) < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
-        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-        ctxt->controlFd = -1;
-	return(-1);
-    }
-
-    /*
-     * Wait for the HELLO from the server.
-     */
-    res = xmlNanoFTPGetResponse(ctxt);
-    if (res != 2) {
-        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-        ctxt->controlFd = -1;
-	return(-1);
-    }
-
-    /*
-     * State diagram for the login operation on the FTP server
-     *
-     * Reference: RFC 959
-     *
-     *                       1
-     * +---+   USER    +---+------------->+---+
-     * | B |---------->| W | 2       ---->| E |
-     * +---+           +---+------  |  -->+---+
-     *                  | |       | | |
-     *                3 | | 4,5   | | |
-     *    --------------   -----  | | |
-     *   |                      | | | |
-     *   |                      | | | |
-     *   |                 ---------  |
-     *   |               1|     | |   |
-     *   V                |     | |   |
-     * +---+   PASS    +---+ 2  |  ------>+---+
-     * |   |---------->| W |------------->| S |
-     * +---+           +---+   ---------->+---+
-     *                  | |   | |     |
-     *                3 | |4,5| |     |
-     *    --------------   --------   |
-     *   |                    | |  |  |
-     *   |                    | |  |  |
-     *   |                 -----------
-     *   |             1,3|   | |  |
-     *   V                |  2| |  |
-     * +---+   ACCT    +---+--  |   ----->+---+
-     * |   |---------->| W | 4,5 -------->| F |
-     * +---+           +---+------------->+---+
-     *
-     * Of course in case of using a proxy this get really nasty and is not
-     * standardized at all :-(
-     */
-    if (proxy) {
-        int len;
-	char buf[400];
-
-        if (proxyUser != NULL) {
-	    /*
-	     * We need proxy auth
-	     */
-	    snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
-            buf[sizeof(buf) - 1] = 0;
-            len = strlen(buf);
-#ifdef DEBUG_FTP
-	    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-	    res = send(ctxt->controlFd, buf, len, 0);
-	    if (res < 0) {
-		__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-		closesocket(ctxt->controlFd);
-		ctxt->controlFd = -1;
-	        return(res);
-	    }
-	    res = xmlNanoFTPGetResponse(ctxt);
-	    switch (res) {
-		case 2:
-		    if (proxyPasswd == NULL)
-			break;
-		case 3:
-		    if (proxyPasswd != NULL)
-			snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
-		    else
-			snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
-                    buf[sizeof(buf) - 1] = 0;
-                    len = strlen(buf);
-#ifdef DEBUG_FTP
-		    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-		    res = send(ctxt->controlFd, buf, len, 0);
-		    if (res < 0) {
-			__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-			closesocket(ctxt->controlFd);
-			ctxt->controlFd = -1;
-			return(res);
-		    }
-		    res = xmlNanoFTPGetResponse(ctxt);
-		    if (res > 3) {
-			closesocket(ctxt->controlFd);
-			ctxt->controlFd = -1;
-			return(-1);
-		    }
-		    break;
-		case 1:
-		    break;
-		case 4:
-		case 5:
-		case -1:
-		default:
-		    closesocket(ctxt->controlFd);
-		    ctxt->controlFd = -1;
-		    return(-1);
-	    }
-	}
-
-	/*
-	 * We assume we don't need more authentication to the proxy
-	 * and that it succeeded :-\
-	 */
-	switch (proxyType) {
-	    case 0:
-		/* we will try in sequence */
-	    case 1:
-		/* Using SITE command */
-		snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
-                buf[sizeof(buf) - 1] = 0;
-                len = strlen(buf);
-#ifdef DEBUG_FTP
-		xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-		res = send(ctxt->controlFd, buf, len, 0);
-		if (res < 0) {
-		    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
-		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-		    ctxt->controlFd = -1;
-		    return(res);
-		}
-		res = xmlNanoFTPGetResponse(ctxt);
-		if (res == 2) {
-		    /* we assume it worked :-\ 1 is error for SITE command */
-		    proxyType = 1;
-		    break;
-		}    
-		if (proxyType == 1) {
-		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-		    ctxt->controlFd = -1;
-		    return(-1);
-		}
-	    case 2:
-		/* USER user@host command */
-		if (ctxt->user == NULL)
-		    snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
-			           ctxt->hostname);
-		else
-		    snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
-			           ctxt->user, ctxt->hostname);
-                buf[sizeof(buf) - 1] = 0;
-                len = strlen(buf);
-#ifdef DEBUG_FTP
-		xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-		res = send(ctxt->controlFd, buf, len, 0);
-		if (res < 0) {
-		    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
-		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-		    ctxt->controlFd = -1;
-		    return(res);
-		}
-		res = xmlNanoFTPGetResponse(ctxt);
-		if ((res == 1) || (res == 2)) {
-		    /* we assume it worked :-\ */
-		    proxyType = 2;
-		    return(0);
-		}    
-		if (ctxt->passwd == NULL)
-		    snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
-		else
-		    snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
-                buf[sizeof(buf) - 1] = 0;
-                len = strlen(buf);
-#ifdef DEBUG_FTP
-		xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-		res = send(ctxt->controlFd, buf, len, 0);
-		if (res < 0) {
-		    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
-		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-		    ctxt->controlFd = -1;
-		    return(res);
-		}
-		res = xmlNanoFTPGetResponse(ctxt);
-		if ((res == 1) || (res == 2)) {
-		    /* we assume it worked :-\ */
-		    proxyType = 2;
-		    return(0);
-		}
-		if (proxyType == 2) {
-		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-		    ctxt->controlFd = -1;
-		    return(-1);
-		}
-	    case 3:
-		/*
-		 * If you need support for other Proxy authentication scheme
-		 * send the code or at least the sequence in use.
-		 */
-	    default:
-		closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-		ctxt->controlFd = -1;
-		return(-1);
-	}
-    }
-    /*
-     * Non-proxy handling.
-     */
-    res = xmlNanoFTPSendUser(ctxt);
-    if (res < 0) {
-        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-        ctxt->controlFd = -1;
-	return(-1);
-    }
-    res = xmlNanoFTPGetResponse(ctxt);
-    switch (res) {
-	case 2:
-	    return(0);
-	case 3:
-	    break;
-	case 1:
-	case 4:
-	case 5:
-        case -1:
-	default:
-	    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-	    ctxt->controlFd = -1;
-	    return(-1);
-    }
-    res = xmlNanoFTPSendPasswd(ctxt);
-    if (res < 0) {
-        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-        ctxt->controlFd = -1;
-	return(-1);
-    }
-    res = xmlNanoFTPGetResponse(ctxt);
-    switch (res) {
-	case 2:
-	    break;
-	case 3:
-	    __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
-		       "FTP server asking for ACCNT on anonymous\n");
-	case 1:
-	case 4:
-	case 5:
-        case -1:
-	default:
-	    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-	    ctxt->controlFd = -1;
-	    return(-1);
-    }
-
-    return(0);
-}
-
-/**
- * xmlNanoFTPConnectTo:
- * @server:  an FTP server name
- * @port:  the port (use 21 if 0)
- *
- * Tries to open a control connection to the given server/port
- *
- * Returns an fTP context or NULL if it failed
- */
-
-void*
-xmlNanoFTPConnectTo(const char *server, int port) {
-    xmlNanoFTPCtxtPtr ctxt;
-    int res;
-
-    xmlNanoFTPInit();
-    if (server == NULL) 
-	return(NULL);
-    if (port <= 0)
-	return(NULL);
-    ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
-    ctxt->hostname = xmlMemStrdup(server);
-    if (port != 0)
-	ctxt->port = port;
-    res = xmlNanoFTPConnect(ctxt);
-    if (res < 0) {
-	xmlNanoFTPFreeCtxt(ctxt);
-	return(NULL);
-    }
-    return(ctxt);
-}
-
-/**
- * xmlNanoFTPCwd:
- * @ctx:  an FTP context
- * @directory:  a directory on the server
- *
- * Tries to change the remote directory
- *
- * Returns -1 incase of error, 1 if CWD worked, 0 if it failed
- */
-
-int
-xmlNanoFTPCwd(void *ctx, const char *directory) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[400];
-    int len;
-    int res;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-    if (directory == NULL) return 0;
-
-    /*
-     * Expected response code for CWD:
-     *
-     * CWD
-     *     250
-     *     500, 501, 502, 421, 530, 550
-     */
-    snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
-    buf[sizeof(buf) - 1] = 0;
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	return(res);
-    }
-    res = xmlNanoFTPGetResponse(ctxt);
-    if (res == 4) {
-	return(-1);
-    }
-    if (res == 2) return(1);
-    if (res == 5) {
-	return(0);
-    }
-    return(0);
-}
-
-/**
- * xmlNanoFTPDele:
- * @ctx:  an FTP context
- * @file:  a file or directory on the server
- *
- * Tries to delete an item (file or directory) from server
- *
- * Returns -1 incase of error, 1 if DELE worked, 0 if it failed
- */
-
-int
-xmlNanoFTPDele(void *ctx, const char *file) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[400];
-    int len;
-    int res;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0) || (file == NULL)) return(-1);
-    if (file == NULL) return (0);
-
-    /*
-     * Expected response code for DELE:
-     *
-     * DELE
-     *       250
-     *       450, 550
-     *       500, 501, 502, 421, 530
-     */
-	 
-    snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
-    buf[sizeof(buf) - 1] = 0;
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	return(res);
-    }
-    res = xmlNanoFTPGetResponse(ctxt);
-    if (res == 4) {
-	return(-1);
-    }
-    if (res == 2) return(1);
-    if (res == 5) {
-	return(0);
-    }
-    return(0);
-}
-/**
- * xmlNanoFTPGetConnection:
- * @ctx:  an FTP context
- *
- * Try to open a data connection to the server. Currently only
- * passive mode is supported.
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPGetConnection(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[200], *cur;
-    int len, i;
-    int res;
-    unsigned char ad[6], *adp, *portp;
-    unsigned int temp[6];
-#ifdef SUPPORT_IP6
-    struct sockaddr_storage dataAddr;
-#else
-    struct sockaddr_in dataAddr;
-#endif
-    XML_SOCKLEN_T dataAddrLen;
-
-    if (ctxt == NULL) return(-1);
-
-    memset (&dataAddr, 0, sizeof(dataAddr));
-#ifdef SUPPORT_IP6
-    if ((ctxt->ftpAddr).ss_family == AF_INET6) {
-	ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
-	((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
-	dataAddrLen = sizeof(struct sockaddr_in6);
-    } else
-#endif
-    {
-	ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
-	((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
-	dataAddrLen = sizeof (struct sockaddr_in);
-    }
-
-    if (ctxt->dataFd < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "socket failed");
-	return (-1);
-    }
-
-    if (ctxt->passive) {
-#ifdef SUPPORT_IP6
-	if ((ctxt->ftpAddr).ss_family == AF_INET6)
-	    snprintf (buf, sizeof(buf), "EPSV\r\n");
-	else
-#endif
-	    snprintf (buf, sizeof(buf), "PASV\r\n");
-        len = strlen (buf);
-#ifdef DEBUG_FTP
-	xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-	res = send(ctxt->controlFd, buf, len, 0);
-	if (res < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return(res);
-	}
-        res = xmlNanoFTPReadResponse(ctx);
-	if (res != 2) {
-	    if (res == 5) {
-	        closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-		return(-1);
-	    } else {
-		/*
-		 * retry with an active connection
-		 */
-	        closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	        ctxt->passive = 0;
-	    }
-	}
-	cur = &ctxt->controlBuf[ctxt->controlBufAnswer]; 
-	while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
-#ifdef SUPPORT_IP6
-	if ((ctxt->ftpAddr).ss_family == AF_INET6) {
-	    if (sscanf (cur, "%u", &temp[0]) != 1) {
-		__xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
-			"Invalid answer to EPSV\n");
-		if (ctxt->dataFd != -1) {
-		    closesocket (ctxt->dataFd); ctxt->dataFd = -1;
-		}
-		return (-1);
-	    }
-	    memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
-	    ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
-	}
-	else
-#endif
-	{
-	    if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
-		&temp[3], &temp[4], &temp[5]) != 6) {
-		__xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
-			"Invalid answer to PASV\n");
-		if (ctxt->dataFd != -1) {
-		    closesocket (ctxt->dataFd); ctxt->dataFd = -1;
-		}
-		return (-1);
-	    }
-	    for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
-	    memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
-	    memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
-	}
-
-	if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return (-1);
-	}
-    } else {
-        getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
-#ifdef SUPPORT_IP6
-	if ((ctxt->ftpAddr).ss_family == AF_INET6)
-	    ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
-	else
-#endif
-	    ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
-
-	if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return (-1);
-	}
-        getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
-
-	if (listen(ctxt->dataFd, 1) < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return (-1);
-	}
-#ifdef SUPPORT_IP6
-	if ((ctxt->ftpAddr).ss_family == AF_INET6) {
-	    char buf6[INET6_ADDRSTRLEN];
-	    inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
-		    buf6, INET6_ADDRSTRLEN);
-	    adp = (unsigned char *) buf6;
-	    portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
-	    snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
-        } else
-#endif
-	{
-	    adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
-	    portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
-	    snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
-	    adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
-	    portp[0] & 0xff, portp[1] & 0xff);
-	}
-
-        buf[sizeof(buf) - 1] = 0;
-        len = strlen(buf);
-#ifdef DEBUG_FTP
-	xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-
-	res = send(ctxt->controlFd, buf, len, 0);
-	if (res < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return(res);
-	}
-        res = xmlNanoFTPGetResponse(ctxt);
-	if (res != 2) {
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return(-1);
-        }
-    }
-    return(ctxt->dataFd);
-    
-}
-
-/**
- * xmlNanoFTPCloseConnection:
- * @ctx:  an FTP context
- *
- * Close the data connection from the server
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPCloseConnection(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    int res;
-    fd_set rfd, efd;
-    struct timeval tv;
-
-    if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
-
-    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-    tv.tv_sec = 15;
-    tv.tv_usec = 0;
-    FD_ZERO(&rfd);
-    FD_SET(ctxt->controlFd, &rfd);
-    FD_ZERO(&efd);
-    FD_SET(ctxt->controlFd, &efd);
-    res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
-    if (res < 0) {
-#ifdef DEBUG_FTP
-	perror("select");
-#endif
-	closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-	return(-1);
-    }
-    if (res == 0) {
-#ifdef DEBUG_FTP
-	xmlGenericError(xmlGenericErrorContext,
-		"xmlNanoFTPCloseConnection: timeout\n");
-#endif
-	closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-    } else {
-	res = xmlNanoFTPGetResponse(ctxt);
-	if (res != 2) {
-	    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
-	    return(-1);
-	}
-    }
-    return(0);
-}
-
-/**
- * xmlNanoFTPParseList:
- * @list:  some data listing received from the server
- * @callback:  the user callback
- * @userData:  the user callback data
- *
- * Parse at most one entry from the listing. 
- *
- * Returns -1 incase of error, the length of data parsed otherwise
- */
-
-static int
-xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
-    const char *cur = list;
-    char filename[151];
-    char attrib[11];
-    char owner[11];
-    char group[11];
-    char month[4];
-    int year = 0;
-    int minute = 0;
-    int hour = 0;
-    int day = 0;
-    unsigned long size = 0;
-    int links = 0;
-    int i;
-
-    if (!strncmp(cur, "total", 5)) {
-        cur += 5;
-	while (*cur == ' ') cur++;
-	while ((*cur >= '0') && (*cur <= '9'))
-	    links = (links * 10) + (*cur++ - '0');
-	while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
-	    cur++;
-	return(cur - list);
-    } else if (*list == '+') {
-	return(0);
-    } else {
-	while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
-	    cur++;
-	if (*cur == 0) return(0);
-	i = 0;
-	while (*cur != ' ') {
-	    if (i < 10) 
-		attrib[i++] = *cur;
-	    cur++;
-	    if (*cur == 0) return(0);
-	}
-	attrib[10] = 0;
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	while ((*cur >= '0') && (*cur <= '9'))
-	    links = (links * 10) + (*cur++ - '0');
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	i = 0;
-	while (*cur != ' ') {
-	    if (i < 10) 
-		owner[i++] = *cur;
-	    cur++;
-	    if (*cur == 0) return(0);
-	}
-	owner[i] = 0;
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	i = 0;
-	while (*cur != ' ') {
-	    if (i < 10) 
-		group[i++] = *cur;
-	    cur++;
-	    if (*cur == 0) return(0);
-	}
-	group[i] = 0;
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	while ((*cur >= '0') && (*cur <= '9'))
-	    size = (size * 10) + (*cur++ - '0');
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	i = 0;
-	while (*cur != ' ') {
-	    if (i < 3)
-		month[i++] = *cur;
-	    cur++;
-	    if (*cur == 0) return(0);
-	}
-	month[i] = 0;
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-        while ((*cur >= '0') && (*cur <= '9'))
-	    day = (day * 10) + (*cur++ - '0');
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	if ((cur[1] == 0) || (cur[2] == 0)) return(0);
-	if ((cur[1] == ':') || (cur[2] == ':')) {
-	    while ((*cur >= '0') && (*cur <= '9'))
-		hour = (hour * 10) + (*cur++ - '0');
-	    if (*cur == ':') cur++;
-	    while ((*cur >= '0') && (*cur <= '9'))
-		minute = (minute * 10) + (*cur++ - '0');
-	} else {
-	    while ((*cur >= '0') && (*cur <= '9'))
-		year = (year * 10) + (*cur++ - '0');
-	}
-	while (*cur == ' ') cur++;
-	if (*cur == 0) return(0);
-	i = 0;
-	while ((*cur != '\n')  && (*cur != '\r')) {
-	    if (i < 150)
-		filename[i++] = *cur;
-	    cur++;
-	    if (*cur == 0) return(0);
-	}
-	filename[i] = 0;
-	if ((*cur != '\n') && (*cur != '\r'))
-	    return(0);
-	while ((*cur == '\n')  || (*cur == '\r'))
-	    cur++;
-    }
-    if (callback != NULL) {
-        callback(userData, filename, attrib, owner, group, size, links,
-		 year, month, day, hour, minute);
-    }
-    return(cur - list);
-}
-
-/**
- * xmlNanoFTPList:
- * @ctx:  an FTP context
- * @callback:  the user callback
- * @userData:  the user callback data
- * @filename:  optional files to list
- *
- * Do a listing on the server. All files info are passed back
- * in the callbacks.
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
-	       const char *filename) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[4096 + 1];
-    int len, res;
-    int indx = 0, base;
-    fd_set rfd, efd;
-    struct timeval tv;
-
-    if (ctxt == NULL) return (-1);
-    if (filename == NULL) {
-        if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
-	    return(-1);
-	ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
-	if (ctxt->dataFd == -1)
-	    return(-1);
-	snprintf(buf, sizeof(buf), "LIST -L\r\n");
-    } else {
-	if (filename[0] != '/') {
-	    if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
-		return(-1);
-	}
-	ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
-	if (ctxt->dataFd == -1)
-	    return(-1);
-	snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
-    }
-    buf[sizeof(buf) - 1] = 0;
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	return(res);
-    }
-    res = xmlNanoFTPReadResponse(ctxt);
-    if (res != 1) {
-	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	return(-res);
-    }
-
-    do {
-	tv.tv_sec = 1;
-	tv.tv_usec = 0;
-	FD_ZERO(&rfd);
-	FD_SET(ctxt->dataFd, &rfd);
-	FD_ZERO(&efd);
-	FD_SET(ctxt->dataFd, &efd);
-	res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
-	if (res < 0) {
-#ifdef DEBUG_FTP
-	    perror("select");
-#endif
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return(-1);
-	}
-	if (res == 0) {
-	    res = xmlNanoFTPCheckResponse(ctxt);
-	    if (res < 0) {
-		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-		ctxt->dataFd = -1;
-		return(-1);
-	    }
-	    if (res == 2) {
-		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-		return(0);
-	    }
-
-	    continue;
-	}
-
-	if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "recv");
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    ctxt->dataFd = -1;
-	    return(-1);
-	}
-#ifdef DEBUG_FTP
-        write(1, &buf[indx], len);
-#endif
-	indx += len;
-	buf[indx] = 0;
-	base = 0;
-	do {
-	    res = xmlNanoFTPParseList(&buf[base], callback, userData);
-	    base += res;
-	} while (res > 0);
-
-	memmove(&buf[0], &buf[base], indx - base);
-	indx -= base;
-    } while (len != 0);
-    xmlNanoFTPCloseConnection(ctxt);
-    return(0);
-}
-
-/**
- * xmlNanoFTPGetSocket:
- * @ctx:  an FTP context
- * @filename:  the file to retrieve (or NULL if path is in context).
- *
- * Initiate fetch of the given file from the server.
- *
- * Returns the socket for the data connection, or <0 in case of error
- */
-
-
-int
-xmlNanoFTPGetSocket(void *ctx, const char *filename) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[300];
-    int res, len;
-    if (ctx == NULL)
-	return(-1);
-    if ((filename == NULL) && (ctxt->path == NULL))
-	return(-1);
-    ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
-    if (ctxt->dataFd == -1)
-	return(-1);
-
-    snprintf(buf, sizeof(buf), "TYPE I\r\n");
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	return(res);
-    }
-    res = xmlNanoFTPReadResponse(ctxt);
-    if (res != 2) {
-	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	return(-res);
-    }
-    if (filename == NULL)
-	snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
-    else
-	snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
-    buf[sizeof(buf) - 1] = 0;
-    len = strlen(buf);
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "%s", buf);
-#endif
-    res = send(ctxt->controlFd, buf, len, 0);
-    if (res < 0) {
-	__xmlIOErr(XML_FROM_FTP, 0, "send failed");
-	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	return(res);
-    }
-    res = xmlNanoFTPReadResponse(ctxt);
-    if (res != 1) {
-	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	return(-res);
-    }
-    return(ctxt->dataFd);
-}
-
-/**
- * xmlNanoFTPGet:
- * @ctx:  an FTP context
- * @callback:  the user callback
- * @userData:  the user callback data
- * @filename:  the file to retrieve
- *
- * Fetch the given file from the server. All data are passed back
- * in the callbacks. The last callback has a size of 0 block.
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
-	      const char *filename) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-    char buf[4096];
-    int len = 0, res;
-    fd_set rfd;
-    struct timeval tv;
-
-    if (ctxt == NULL) return(-1);
-    if ((filename == NULL) && (ctxt->path == NULL))
-	return(-1);
-    if (callback == NULL)
-	return(-1);
-    if (xmlNanoFTPGetSocket(ctxt, filename) < 0)
-	return(-1);
-
-    do {
-	tv.tv_sec = 1;
-	tv.tv_usec = 0;
-	FD_ZERO(&rfd);
-	FD_SET(ctxt->dataFd, &rfd);
-	res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
-	if (res < 0) {
-#ifdef DEBUG_FTP
-	    perror("select");
-#endif
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return(-1);
-	}
-	if (res == 0) {
-	    res = xmlNanoFTPCheckResponse(ctxt);
-	    if (res < 0) {
-		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-		ctxt->dataFd = -1;
-		return(-1);
-	    }
-	    if (res == 2) {
-		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-		return(0);
-	    }
-
-	    continue;
-	}
-	if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
-	    __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
-	    callback(userData, buf, len);
-	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
-	    return(-1);
-	}
-	callback(userData, buf, len);
-    } while (len != 0);
-
-    return(xmlNanoFTPCloseConnection(ctxt));
-}
-
-/**
- * xmlNanoFTPRead:
- * @ctx:  the FTP context
- * @dest:  a buffer
- * @len:  the buffer length
- *
- * This function tries to read @len bytes from the existing FTP connection
- * and saves them in @dest. This is a blocking call.
- *
- * Returns the number of byte read. 0 is an indication of an end of connection.
- *         -1 indicates a parameter error.
- */
-int
-xmlNanoFTPRead(void *ctx, void *dest, int len) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-
-    if (ctx == NULL) return(-1);
-    if (ctxt->dataFd < 0) return(0);
-    if (dest == NULL) return(-1);
-    if (len <= 0) return(0);
-
-    len = recv(ctxt->dataFd, dest, len, 0);
-    if (len <= 0) {
-	if (len < 0)
-	    __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
-	xmlNanoFTPCloseConnection(ctxt);
-    }
-#ifdef DEBUG_FTP
-    xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
-#endif
-    return(len);
-}
-
-/**
- * xmlNanoFTPOpen:
- * @URL: the URL to the resource
- *
- * Start to fetch the given ftp:// resource
- *
- * Returns an FTP context, or NULL 
- */
-
-void*
-xmlNanoFTPOpen(const char *URL) {
-    xmlNanoFTPCtxtPtr ctxt;
-    int sock;
-
-    xmlNanoFTPInit();
-    if (URL == NULL) return(NULL);
-    if (strncmp("ftp://", URL, 6)) return(NULL);
-
-    ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
-    if (ctxt == NULL) return(NULL);
-    if (xmlNanoFTPConnect(ctxt) < 0) {
-	xmlNanoFTPFreeCtxt(ctxt);
-	return(NULL);
-    }
-    sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
-    if (sock < 0) {
-	xmlNanoFTPFreeCtxt(ctxt);
-	return(NULL);
-    }
-    return(ctxt);
-}
-
-/**
- * xmlNanoFTPClose:
- * @ctx: an FTP context
- *
- * Close the connection and both control and transport
- *
- * Returns -1 incase of error, 0 otherwise
- */
-
-int
-xmlNanoFTPClose(void *ctx) {
-    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
-
-    if (ctxt == NULL)
-	return(-1);
-
-    if (ctxt->dataFd >= 0) {
-	closesocket(ctxt->dataFd);
-	ctxt->dataFd = -1;
-    }
-    if (ctxt->controlFd >= 0) {
-	xmlNanoFTPQuit(ctxt);
-	closesocket(ctxt->controlFd);
-	ctxt->controlFd = -1;
-    }
-    xmlNanoFTPFreeCtxt(ctxt);
-    return(0);
-}
-
-#ifdef STANDALONE
-/************************************************************************
- * 									*
- * 			Basic test in Standalone mode			*
- * 									*
- ************************************************************************/
-static
-void ftpList(void *userData, const char *filename, const char* attrib,
-	     const char *owner, const char *group, unsigned long size, int links,
-	     int year, const char *month, int day, int hour, int minute) {
-    xmlGenericError(xmlGenericErrorContext,
-	    "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
-}
-static
-void ftpData(void *userData, const char *data, int len) {
-    if (userData == NULL) return;
-    if (len <= 0) {
-	fclose((FILE*)userData);
-	return;
-    }	
-    fwrite(data, len, 1, (FILE*)userData);
-}
-
-int main(int argc, char **argv) {
-    void *ctxt;
-    FILE *output;
-    char *tstfile = NULL;
-
-    xmlNanoFTPInit();
-    if (argc > 1) {
-	ctxt = xmlNanoFTPNewCtxt(argv[1]);
-	if (xmlNanoFTPConnect(ctxt) < 0) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "Couldn't connect to %s\n", argv[1]);
-	    exit(1);
-	}
-	if (argc > 2)
-	    tstfile = argv[2];
-    } else
-	ctxt = xmlNanoFTPConnectTo("localhost", 0);
-    if (ctxt == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		"Couldn't connect to localhost\n");
-        exit(1);
-    }
-    xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
-    output = fopen("/tmp/tstdata", "w");
-    if (output != NULL) {
-	if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
-	    xmlGenericError(xmlGenericErrorContext,
-		    "Failed to get file\n");
-	
-    }
-    xmlNanoFTPClose(ctxt);
-    xmlMemoryDump();
-    exit(0);
-}
-#endif /* STANDALONE */
-#else /* !LIBXML_FTP_ENABLED */
-#ifdef STANDALONE
-#include <stdio.h>
-int main(int argc, char **argv) {
-    xmlGenericError(xmlGenericErrorContext,
-	    "%s : FTP support not compiled in\n", argv[0]);
-    return(0);
-}
-#endif /* STANDALONE */
-#endif /* LIBXML_FTP_ENABLED */
-#define bottom_nanoftp
-#include "elfgcchack.h"
diff --git a/third_party/libxml/src/nanohttp.c b/third_party/libxml/src/nanohttp.c
deleted file mode 100644
index 542c4ea..0000000
--- a/third_party/libxml/src/nanohttp.c
+++ /dev/null
@@ -1,1875 +0,0 @@
-/*
- * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets.
- *             focuses on size, streamability, reentrancy and portability
- *
- * This is clearly not a general purpose HTTP implementation
- * If you look for one, check:
- *         http://www.w3.org/Library/
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
- 
-#define NEED_SOCKETS
-#define IN_LIBXML
-#include "libxml.h"
-
-#ifdef LIBXML_HTTP_ENABLED
-#include <string.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_RESOLV_H
-#ifdef HAVE_ARPA_NAMESER_H
-#include <arpa/nameser.h>
-#endif
-#include <resolv.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h> 
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifndef HAVE_POLL_H
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#else
-#include <poll.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#ifdef SUPPORT_IP6
-#include <resolv.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-
-#ifdef VMS
-#include <stropts>
-#define XML_SOCKLEN_T unsigned int
-#define SOCKET int
-#endif
-
-#if defined(__MINGW32__) || defined(_WIN32_WCE)
-#define _WINSOCKAPI_
-#include <wsockcompat.h>
-#include <winsock2.h>
-#undef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-
-
-#include <libxml/globals.h>
-#include <libxml/xmlerror.h>
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
-#include <libxml/nanohttp.h>
-#include <libxml/globals.h>
-#include <libxml/uri.h>
-
-/**
- * A couple portability macros
- */
-#ifndef _WINSOCKAPI_
-#if !defined(__BEOS__) || defined(__HAIKU__)
-#define closesocket(s) close(s)
-#endif
-#define SOCKET int
-#endif
-
-#ifdef __BEOS__
-#ifndef PF_INET
-#define PF_INET AF_INET
-#endif
-#endif
-
-#ifndef XML_SOCKLEN_T
-#define XML_SOCKLEN_T unsigned int
-#endif
-#ifndef SOCKET
-#define SOCKET int
-#endif
-
-#ifdef STANDALONE
-#define DEBUG_HTTP
-#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
-#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
-#endif
-
-#define XML_NANO_HTTP_MAX_REDIR	10
-
-#define XML_NANO_HTTP_CHUNK	4096
-
-#define XML_NANO_HTTP_CLOSED	0
-#define XML_NANO_HTTP_WRITE	1
-#define XML_NANO_HTTP_READ	2
-#define XML_NANO_HTTP_NONE	4
-
-typedef struct xmlNanoHTTPCtxt {
-    char *protocol;	/* the protocol name */
-    char *hostname;	/* the host name */
-    int port;		/* the port */
-    char *path;		/* the path within the URL */
-    char *query;	/* the query string */
-    SOCKET fd;		/* the file descriptor for the socket */
-    int state;		/* WRITE / READ / CLOSED */
-    char *out;		/* buffer sent (zero terminated) */
-    char *outptr;	/* index within the buffer sent */
-    char *in;		/* the receiving buffer */
-    char *content;	/* the start of the content */
-    char *inptr;	/* the next byte to read from network */
-    char *inrptr;	/* the next byte to give back to the client */
-    int inlen;		/* len of the input buffer */
-    int last;		/* return code for last operation */
-    int returnValue;	/* the protocol return value */
-    int version;        /* the protocol version */
-    int ContentLength;  /* specified content length from HTTP header */
-    char *contentType;	/* the MIME type for the input */
-    char *location;	/* the new URL in case of redirect */
-    char *authHeader;	/* contents of {WWW,Proxy}-Authenticate header */
-    char *encoding;	/* encoding extracted from the contentType */
-    char *mimeType;	/* Mime-Type extracted from the contentType */
-#ifdef HAVE_ZLIB_H
-    z_stream *strm;	/* Zlib stream object */
-    int usesGzip;	/* "Content-Encoding: gzip" was detected */
-#endif
-} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
-
-static int initialized = 0;
-static char *proxy = NULL;	 /* the proxy name if any */
-static int proxyPort;	/* the proxy port if any */
-static unsigned int timeout = 60;/* the select() timeout in seconds */
-
-static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len );
-
-/**
- * xmlHTTPErrMemory:
- * @extra:  extra informations
- *
- * Handle an out of memory condition
- */
-static void
-xmlHTTPErrMemory(const char *extra)
-{
-    __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
-}
-
-/**
- * A portability function
- */
-static int socket_errno(void) {
-#ifdef _WINSOCKAPI_
-    return(WSAGetLastError());
-#else
-    return(errno);
-#endif
-}
-
-#ifdef SUPPORT_IP6
-static
-int have_ipv6(void) {
-    int s;
-
-    s = socket (AF_INET6, SOCK_STREAM, 0);
-    if (s != -1) {
-	close (s);
-	return (1);
-    }
-    return (0);
-}
-#endif
-
-/**
- * xmlNanoHTTPInit:
- *
- * Initialize the HTTP protocol layer.
- * Currently it just checks for proxy informations
- */
-
-void
-xmlNanoHTTPInit(void) {
-    const char *env;
-#ifdef _WINSOCKAPI_
-    WSADATA wsaData;    
-#endif
-
-    if (initialized)
-	return;
-
-#ifdef _WINSOCKAPI_
-    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
-	return;
-#endif
-
-    if (proxy == NULL) {
-	proxyPort = 80;
-	env = getenv("no_proxy");
-	if (env && ((env[0] == '*') && (env[1] == 0)))
-	    goto done;
-	env = getenv("http_proxy");
-	if (env != NULL) {
-	    xmlNanoHTTPScanProxy(env);
-	    goto done;
-	}
-	env = getenv("HTTP_PROXY");
-	if (env != NULL) {
-	    xmlNanoHTTPScanProxy(env);
-	    goto done;
-	}
-    }
-done:
-    initialized = 1;
-}
-
-/**
- * xmlNanoHTTPCleanup:
- *
- * Cleanup the HTTP protocol layer.
- */
-
-void
-xmlNanoHTTPCleanup(void) {
-    if (proxy != NULL) {
-	xmlFree(proxy);
-	proxy = NULL;
-    }
-#ifdef _WINSOCKAPI_
-    if (initialized)
-	WSACleanup();
-#endif
-    initialized = 0;
-    return;
-}
-
-/**
- * xmlNanoHTTPScanURL:
- * @ctxt:  an HTTP context
- * @URL:  The URL used to initialize the context
- *
- * (Re)Initialize an HTTP context by parsing the URL and finding
- * the protocol host port and path it indicates.
- */
-
-static void
-xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
-    xmlURIPtr uri;
-    /*
-     * Clear any existing data from the context
-     */
-    if (ctxt->protocol != NULL) { 
-        xmlFree(ctxt->protocol);
-	ctxt->protocol = NULL;
-    }
-    if (ctxt->hostname != NULL) { 
-        xmlFree(ctxt->hostname);
-	ctxt->hostname = NULL;
-    }
-    if (ctxt->path != NULL) { 
-        xmlFree(ctxt->path);
-	ctxt->path = NULL;
-    }
-    if (ctxt->query != NULL) { 
-        xmlFree(ctxt->query);
-	ctxt->query = NULL;
-    }
-    if (URL == NULL) return;
-
-    uri = xmlParseURIRaw(URL, 1);
-    if (uri == NULL)
-	return;
-
-    if ((uri->scheme == NULL) || (uri->server == NULL)) {
-	xmlFreeURI(uri);
-	return;
-    }
-    
-    ctxt->protocol = xmlMemStrdup(uri->scheme);
-    ctxt->hostname = xmlMemStrdup(uri->server);
-    if (uri->path != NULL)
-	ctxt->path = xmlMemStrdup(uri->path);
-    else
-	ctxt->path = xmlMemStrdup("/");
-    if (uri->query != NULL)
-	ctxt->query = xmlMemStrdup(uri->query);
-    if (uri->port != 0)
-	ctxt->port = uri->port;
-
-    xmlFreeURI(uri);
-}
-
-/**
- * xmlNanoHTTPScanProxy:
- * @URL:  The proxy URL used to initialize the proxy context
- *
- * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
- * the protocol host port it indicates.
- * Should be like http://myproxy/ or http://myproxy:3128/
- * A NULL URL cleans up proxy informations.
- */
-
-void
-xmlNanoHTTPScanProxy(const char *URL) {
-    xmlURIPtr uri;
-
-    if (proxy != NULL) { 
-        xmlFree(proxy);
-	proxy = NULL;
-    }
-    proxyPort = 0;
-
-#ifdef DEBUG_HTTP
-    if (URL == NULL)
-	xmlGenericError(xmlGenericErrorContext,
-		"Removing HTTP proxy info\n");
-    else
-	xmlGenericError(xmlGenericErrorContext,
-		"Using HTTP proxy %s\n", URL);
-#endif
-    if (URL == NULL) return;
-
-    uri = xmlParseURIRaw(URL, 1);
-    if ((uri == NULL) || (uri->scheme == NULL) ||
-	(strcmp(uri->scheme, "http")) || (uri->server == NULL)) {
-	__xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Syntax Error\n");
-	if (uri != NULL)
-	    xmlFreeURI(uri);
-	return;
-    }
-    
-    proxy = xmlMemStrdup(uri->server);
-    if (uri->port != 0)
-	proxyPort = uri->port;
-
-    xmlFreeURI(uri);
-}
-
-/**
- * xmlNanoHTTPNewCtxt:
- * @URL:  The URL used to initialize the context
- *
- * Allocate and initialize a new HTTP context.
- *
- * Returns an HTTP context or NULL in case of error.
- */
-
-static xmlNanoHTTPCtxtPtr
-xmlNanoHTTPNewCtxt(const char *URL) {
-    xmlNanoHTTPCtxtPtr ret;
-
-    ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
-    if (ret == NULL) {
-        xmlHTTPErrMemory("allocating context");
-        return(NULL);
-    }
-
-    memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
-    ret->port = 80;
-    ret->returnValue = 0;
-    ret->fd = -1;
-    ret->ContentLength = -1;
-
-    xmlNanoHTTPScanURL(ret, URL);
-
-    return(ret);
-}
-
-/**
- * xmlNanoHTTPFreeCtxt:
- * @ctxt:  an HTTP context
- *
- * Frees the context after closing the connection.
- */
-
-static void
-xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
-    if (ctxt == NULL) return;
-    if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
-    if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
-    if (ctxt->path != NULL) xmlFree(ctxt->path);
-    if (ctxt->query != NULL) xmlFree(ctxt->query);
-    if (ctxt->out != NULL) xmlFree(ctxt->out);
-    if (ctxt->in != NULL) xmlFree(ctxt->in);
-    if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
-    if (ctxt->encoding != NULL) xmlFree(ctxt->encoding);
-    if (ctxt->mimeType != NULL) xmlFree(ctxt->mimeType);
-    if (ctxt->location != NULL) xmlFree(ctxt->location);
-    if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
-#ifdef HAVE_ZLIB_H
-    if (ctxt->strm != NULL) {
-	inflateEnd(ctxt->strm);
-	xmlFree(ctxt->strm);
-    }
-#endif
-
-    ctxt->state = XML_NANO_HTTP_NONE;
-    if (ctxt->fd >= 0) closesocket(ctxt->fd);
-    ctxt->fd = -1;
-    xmlFree(ctxt);
-}
-
-/**
- * xmlNanoHTTPSend:
- * @ctxt:  an HTTP context
- *
- * Send the input needed to initiate the processing on the server side
- * Returns number of bytes sent or -1 on error.
- */
-
-static int
-xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char *xmt_ptr, int outlen)
-{
-    int total_sent = 0;
-#ifdef HAVE_POLL_H
-    struct pollfd p;
-#else
-    struct timeval tv;
-    fd_set wfd;
-#endif
-
-    if ((ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL)) {
-        while (total_sent < outlen) {
-            int nsent = send(ctxt->fd, xmt_ptr + total_sent,
-                             outlen - total_sent, 0);
-
-            if (nsent > 0)
-                total_sent += nsent;
-            else if ((nsent == -1) &&
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
-                     (socket_errno() != EAGAIN) &&
-#endif
-                     (socket_errno() != EWOULDBLOCK)) {
-                __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n");
-                if (total_sent == 0)
-                    total_sent = -1;
-                break;
-            } else {
-                /*
-                 * No data sent
-                 * Since non-blocking sockets are used, wait for
-                 * socket to be writable or default timeout prior
-                 * to retrying.
-                 */
-#ifndef HAVE_POLL_H
-#ifndef _WINSOCKAPI_
-                if (ctxt->fd > FD_SETSIZE)
-                    return -1;
-#endif
-
-                tv.tv_sec = timeout;
-                tv.tv_usec = 0;
-                FD_ZERO(&wfd);
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4018)
-#endif
-                FD_SET(ctxt->fd, &wfd);
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-                (void) select(ctxt->fd + 1, NULL, &wfd, NULL, &tv);
-#else
-                p.fd = ctxt->fd;
-                p.events = POLLOUT;
-                (void) poll(&p, 1, timeout * 1000);
-#endif /* !HAVE_POLL_H */
-            }
-        }
-    }
-
-    return total_sent;
-}
-
-/**
- * xmlNanoHTTPRecv:
- * @ctxt:  an HTTP context
- *
- * Read information coming from the HTTP connection.
- * This is a blocking call (but it blocks in select(), not read()).
- *
- * Returns the number of byte read or -1 in case of error.
- */
-
-static int
-xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt)
-{
-#ifdef HAVE_POLL_H
-    struct pollfd p;
-#else
-    fd_set rfd;
-    struct timeval tv;
-#endif
-
-
-    while (ctxt->state & XML_NANO_HTTP_READ) {
-        if (ctxt->in == NULL) {
-            ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char));
-            if (ctxt->in == NULL) {
-                xmlHTTPErrMemory("allocating input");
-                ctxt->last = -1;
-                return (-1);
-            }
-            ctxt->inlen = 65000;
-            ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
-        }
-        if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
-            int delta = ctxt->inrptr - ctxt->in;
-            int len = ctxt->inptr - ctxt->inrptr;
-
-            memmove(ctxt->in, ctxt->inrptr, len);
-            ctxt->inrptr -= delta;
-            ctxt->content -= delta;
-            ctxt->inptr -= delta;
-        }
-        if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
-            int d_inptr = ctxt->inptr - ctxt->in;
-            int d_content = ctxt->content - ctxt->in;
-            int d_inrptr = ctxt->inrptr - ctxt->in;
-            char *tmp_ptr = ctxt->in;
-
-            ctxt->inlen *= 2;
-            ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
-            if (ctxt->in == NULL) {
-                xmlHTTPErrMemory("allocating input buffer");
-                xmlFree(tmp_ptr);
-                ctxt->last = -1;
-                return (-1);
-            }
-            ctxt->inptr = ctxt->in + d_inptr;
-            ctxt->content = ctxt->in + d_content;
-            ctxt->inrptr = ctxt->in + d_inrptr;
-        }
-        ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
-        if (ctxt->last > 0) {
-            ctxt->inptr += ctxt->last;
-            return (ctxt->last);
-        }
-        if (ctxt->last == 0) {
-            return (0);
-        }
-        if (ctxt->last == -1) {
-            switch (socket_errno()) {
-                case EINPROGRESS:
-                case EWOULDBLOCK:
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
-                case EAGAIN:
-#endif
-                    break;
-
-                case ECONNRESET:
-                case ESHUTDOWN:
-                    return (0);
-
-                default:
-                    __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n");
-                    return (-1);
-            }
-        }
-#ifdef HAVE_POLL_H
-        p.fd = ctxt->fd;
-        p.events = POLLIN;
-        if ((poll(&p, 1, timeout * 1000) < 1)
-#if defined(EINTR)
-            && (errno != EINTR)
-#endif
-            )
-            return (0);
-#else /* !HAVE_POLL_H */
-#ifndef _WINSOCKAPI_
-        if (ctxt->fd > FD_SETSIZE)
-            return 0;
-#endif
-
-        tv.tv_sec = timeout;
-        tv.tv_usec = 0;
-        FD_ZERO(&rfd);
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4018)
-#endif
-
-        FD_SET(ctxt->fd, &rfd);
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-        if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1)
-#if defined(EINTR)
-            && (errno != EINTR)
-#endif
-            )
-            return (0);
-#endif /* !HAVE_POLL_H */
-    }
-    return (0);
-}
-
-/**
- * xmlNanoHTTPReadLine:
- * @ctxt:  an HTTP context
- *
- * Read one line in the HTTP server output, usually for extracting
- * the HTTP protocol informations from the answer header.
- *
- * Returns a newly allocated string with a copy of the line, or NULL
- *         which indicate the end of the input.
- */
-
-static char *
-xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
-    char buf[4096];
-    char *bp = buf;
-    int	rc;
-    
-    while (bp - buf < 4095) {
-	if (ctxt->inrptr == ctxt->inptr) {
-	    if ( (rc = xmlNanoHTTPRecv(ctxt)) == 0) {
-		if (bp == buf)
-		    return(NULL);
-		else
-		    *bp = 0;
-		return(xmlMemStrdup(buf));
-	    }
-	    else if ( rc == -1 ) {
-	        return ( NULL );
-	    }
-	}
-	*bp = *ctxt->inrptr++;
-	if (*bp == '\n') {
-	    *bp = 0;
-	    return(xmlMemStrdup(buf));
-	}
-	if (*bp != '\r')
-	    bp++;
-    }
-    buf[4095] = 0;
-    return(xmlMemStrdup(buf));
-}
-
-
-/**
- * xmlNanoHTTPScanAnswer:
- * @ctxt:  an HTTP context
- * @line:  an HTTP header line
- *
- * Try to extract useful informations from the server answer.
- * We currently parse and process:
- *  - The HTTP revision/ return code
- *  - The Content-Type, Mime-Type and charset used
- *  - The Location for redirect processing.
- *
- * Returns -1 in case of failure, the file descriptor number otherwise
- */
-
-static void
-xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
-    const char *cur = line;
-
-    if (line == NULL) return;
-
-    if (!strncmp(line, "HTTP/", 5)) {
-        int version = 0;
-	int ret = 0;
-
-	cur += 5;
-	while ((*cur >= '0') && (*cur <= '9')) {
-	    version *= 10;
-	    version += *cur - '0';
-	    cur++;
-	}
-	if (*cur == '.') {
-	    cur++;
-	    if ((*cur >= '0') && (*cur <= '9')) {
-		version *= 10;
-		version += *cur - '0';
-		cur++;
-	    }
-	    while ((*cur >= '0') && (*cur <= '9'))
-		cur++;
-	} else
-	    version *= 10;
-	if ((*cur != ' ') && (*cur != '\t')) return;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	if ((*cur < '0') || (*cur > '9')) return;
-	while ((*cur >= '0') && (*cur <= '9')) {
-	    ret *= 10;
-	    ret += *cur - '0';
-	    cur++;
-	}
-	if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
-	ctxt->returnValue = ret;
-        ctxt->version = version;
-    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
-        const xmlChar *charset, *last, *mime;
-        cur += 13;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	if (ctxt->contentType != NULL)
-	    xmlFree(ctxt->contentType);
-	ctxt->contentType = xmlMemStrdup(cur);
-	mime = (const xmlChar *) cur;
-	last = mime;
-	while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
-	       (*last != ';') && (*last != ','))
-	    last++;
-	if (ctxt->mimeType != NULL)
-	    xmlFree(ctxt->mimeType);
-	ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
-	charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
-	if (charset != NULL) {
-	    charset += 8;
-	    last = charset;
-	    while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
-	           (*last != ';') && (*last != ','))
-		last++;
-	    if (ctxt->encoding != NULL)
-	        xmlFree(ctxt->encoding);
-	    ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
-	}
-    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
-        const xmlChar *charset, *last, *mime;
-        cur += 12;
-	if (ctxt->contentType != NULL) return;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	ctxt->contentType = xmlMemStrdup(cur);
-	mime = (const xmlChar *) cur;
-	last = mime;
-	while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
-	       (*last != ';') && (*last != ','))
-	    last++;
-	if (ctxt->mimeType != NULL)
-	    xmlFree(ctxt->mimeType);
-	ctxt->mimeType = (char *) xmlStrndup(mime, last - mime);
-	charset = xmlStrstr(BAD_CAST ctxt->contentType, BAD_CAST "charset=");
-	if (charset != NULL) {
-	    charset += 8;
-	    last = charset;
-	    while ((*last != 0) && (*last != ' ') && (*last != '\t') &&
-	           (*last != ';') && (*last != ','))
-		last++;
-	    if (ctxt->encoding != NULL)
-	        xmlFree(ctxt->encoding);
-	    ctxt->encoding = (char *) xmlStrndup(charset, last - charset);
-	}
-    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
-        cur += 9;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	if (ctxt->location != NULL)
-	    xmlFree(ctxt->location);
-	if (*cur == '/') {
-	    xmlChar *tmp_http = xmlStrdup(BAD_CAST "http://");
-	    xmlChar *tmp_loc = 
-	        xmlStrcat(tmp_http, (const xmlChar *) ctxt->hostname);
-	    ctxt->location = 
-	        (char *) xmlStrcat (tmp_loc, (const xmlChar *) cur);
-	} else {
-	    ctxt->location = xmlMemStrdup(cur);
-	}
-    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
-        cur += 17;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	if (ctxt->authHeader != NULL)
-	    xmlFree(ctxt->authHeader);
-	ctxt->authHeader = xmlMemStrdup(cur);
-    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
-        cur += 19;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	if (ctxt->authHeader != NULL)
-	    xmlFree(ctxt->authHeader);
-	ctxt->authHeader = xmlMemStrdup(cur);
-#ifdef HAVE_ZLIB_H
-    } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Encoding:", 17) ) {
-	cur += 17;
-	while ((*cur == ' ') || (*cur == '\t')) cur++;
-	if ( !xmlStrncasecmp( BAD_CAST cur, BAD_CAST"gzip", 4) ) {
-	    ctxt->usesGzip = 1;
-
-	    ctxt->strm = xmlMalloc(sizeof(z_stream));
-
-	    if (ctxt->strm != NULL) {
-		ctxt->strm->zalloc = Z_NULL;
-		ctxt->strm->zfree = Z_NULL;
-		ctxt->strm->opaque = Z_NULL;
-		ctxt->strm->avail_in = 0;
-		ctxt->strm->next_in = Z_NULL;
-
-		inflateInit2( ctxt->strm, 31 );
-	    }
-	}
-#endif
-    } else if ( !xmlStrncasecmp( BAD_CAST line, BAD_CAST"Content-Length:", 15) ) {
-	cur += 15;
-	ctxt->ContentLength = strtol( cur, NULL, 10 );
-    }
-}
-
-/**
- * xmlNanoHTTPConnectAttempt:
- * @addr:  a socket address structure
- *
- * Attempt a connection to the given IP:port endpoint. It forces
- * non-blocking semantic on the socket, and allow 60 seconds for
- * the host to answer.
- *
- * Returns -1 in case of failure, the file descriptor number otherwise
- */
-
-static int
-xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
-{
-#ifndef HAVE_POLL_H
-    fd_set wfd;
-#ifdef _WINSOCKAPI_
-    fd_set xfd;
-#endif
-    struct timeval tv;
-#else /* !HAVE_POLL_H */
-    struct pollfd p;
-#endif /* !HAVE_POLL_H */
-    int status;
-
-    int addrlen;
-
-    SOCKET s;
-
-#ifdef SUPPORT_IP6
-    if (addr->sa_family == AF_INET6) {
-        s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
-        addrlen = sizeof(struct sockaddr_in6);
-    } else
-#endif
-    {
-        s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-        addrlen = sizeof(struct sockaddr_in);
-    }
-    if (s == -1) {
-#ifdef DEBUG_HTTP
-        perror("socket");
-#endif
-        __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n");
-        return (-1);
-    }
-#ifdef _WINSOCKAPI_
-    {
-        u_long one = 1;
-
-        status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
-    }
-#else /* _WINSOCKAPI_ */
-#if defined(VMS)
-    {
-        int enable = 1;
-
-        status = ioctl(s, FIONBIO, &enable);
-    }
-#else /* VMS */
-#if defined(__BEOS__) && !defined(__HAIKU__)
-    {
-        bool noblock = true;
-
-        status =
-            setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock,
-                       sizeof(noblock));
-    }
-#else /* __BEOS__ */
-    if ((status = fcntl(s, F_GETFL, 0)) != -1) {
-#ifdef O_NONBLOCK
-        status |= O_NONBLOCK;
-#else /* O_NONBLOCK */
-#ifdef F_NDELAY
-        status |= F_NDELAY;
-#endif /* F_NDELAY */
-#endif /* !O_NONBLOCK */
-        status = fcntl(s, F_SETFL, status);
-    }
-    if (status < 0) {
-#ifdef DEBUG_HTTP
-        perror("nonblocking");
-#endif
-        __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n");
-        closesocket(s);
-        return (-1);
-    }
-#endif /* !__BEOS__ */
-#endif /* !VMS */
-#endif /* !_WINSOCKAPI_ */
-
-    if (connect(s, addr, addrlen) == -1) {
-        switch (socket_errno()) {
-            case EINPROGRESS:
-            case EWOULDBLOCK:
-                break;
-            default:
-                __xmlIOErr(XML_FROM_HTTP, 0,
-                           "error connecting to HTTP server");
-                closesocket(s);
-                return (-1);
-        }
-    }
-#ifndef HAVE_POLL_H
-    tv.tv_sec = timeout;
-    tv.tv_usec = 0;
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4018)
-#endif
-#ifndef _WINSOCKAPI_
-    if (s > FD_SETSIZE)
-        return -1;
-#endif
-    FD_ZERO(&wfd);
-    FD_SET(s, &wfd);
-
-#ifdef _WINSOCKAPI_
-    FD_ZERO(&xfd);
-    FD_SET(s, &xfd);
-
-    switch (select(s + 1, NULL, &wfd, &xfd, &tv))
-#else
-    switch (select(s + 1, NULL, &wfd, NULL, &tv))
-#endif
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#else /* !HAVE_POLL_H */
-    p.fd = s;
-    p.events = POLLOUT;
-    switch (poll(&p, 1, timeout * 1000))
-#endif /* !HAVE_POLL_H */
-
-    {
-        case 0:
-            /* Time out */
-            __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out");
-            closesocket(s);
-            return (-1);
-        case -1:
-            /* Ermm.. ?? */
-            __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed");
-            closesocket(s);
-            return (-1);
-    }
-
-#ifndef HAVE_POLL_H
-    if (FD_ISSET(s, &wfd)
-#ifdef _WINSOCKAPI_
-        || FD_ISSET(s, &xfd)
-#endif
-        )
-#else /* !HAVE_POLL_H */
-    if (p.revents == POLLOUT)
-#endif /* !HAVE_POLL_H */
-    {
-        XML_SOCKLEN_T len;
-
-        len = sizeof(status);
-#ifdef SO_ERROR
-        if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) <
-            0) {
-            /* Solaris error code */
-            __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n");
-            return (-1);
-        }
-#endif
-        if (status) {
-            __xmlIOErr(XML_FROM_HTTP, 0,
-                       "Error connecting to remote host");
-            closesocket(s);
-            errno = status;
-            return (-1);
-        }
-    } else {
-        /* pbm */
-        __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n");
-        closesocket(s);
-        return (-1);
-    }
-
-    return (s);
-}
-
-/**
- * xmlNanoHTTPConnectHost:
- * @host:  the host name
- * @port:  the port number
- *
- * Attempt a connection to the given host:port endpoint. It tries
- * the multiple IP provided by the DNS if available.
- *
- * Returns -1 in case of failure, the file descriptor number otherwise
- */
-
-static int
-xmlNanoHTTPConnectHost(const char *host, int port)
-{
-    struct hostent *h;
-    struct sockaddr *addr = NULL;
-    struct in_addr ia;
-    struct sockaddr_in sockin;
-
-#ifdef SUPPORT_IP6
-    struct in6_addr ia6;
-    struct sockaddr_in6 sockin6;
-#endif
-    int i;
-    int s;
-
-    memset (&sockin, 0, sizeof(sockin));
-#ifdef SUPPORT_IP6
-    memset (&sockin6, 0, sizeof(sockin6));
-#endif
-
-#if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6)
-    if (have_ipv6 ())
-    {
-	if (!(_res.options & RES_INIT))
-	    res_init();
-	_res.options |= RES_USE_INET6;
-    }
-#endif
-
-#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
-    if (have_ipv6 ())
-#endif
-#if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32))
-    {
-	int status;
-	struct addrinfo hints, *res, *result;
-
-	result = NULL;
-	memset (&hints, 0,sizeof(hints));
-	hints.ai_socktype = SOCK_STREAM;
-
-	status = getaddrinfo (host, NULL, &hints, &result);
-	if (status) {
-	    __xmlIOErr(XML_FROM_HTTP, 0, "getaddrinfo failed\n");
-	    return (-1);
-	}
-
-	for (res = result; res; res = res->ai_next) {
-	    if (res->ai_family == AF_INET) {
-		if (res->ai_addrlen > sizeof(sockin)) {
-		    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
-		    freeaddrinfo (result);
-		    return (-1);
-		}
-		memcpy (&sockin, res->ai_addr, res->ai_addrlen);
-		sockin.sin_port = htons (port);
-		addr = (struct sockaddr *)&sockin;
-#ifdef SUPPORT_IP6
-	    } else if (have_ipv6 () && (res->ai_family == AF_INET6)) {
-		if (res->ai_addrlen > sizeof(sockin6)) {
-		    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
-		    freeaddrinfo (result);
-		    return (-1);
-		}
-		memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
-		sockin6.sin6_port = htons (port);
-		addr = (struct sockaddr *)&sockin6;
-#endif
-	    } else
-		continue;              /* for */
-
-	    s = xmlNanoHTTPConnectAttempt (addr);
-	    if (s != -1) {
-		freeaddrinfo (result);
-		return (s);
-	    }
-	}
-
-	if (result)
-	    freeaddrinfo (result);
-    }
-#endif
-#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32)
-    else
-#endif
-#if !defined(HAVE_GETADDRINFO) || !defined(_WIN32)
-    {
-	h = gethostbyname (host);
-	if (h == NULL) {
-
-/*
- * Okay, I got fed up by the non-portability of this error message
- * extraction code. it work on Linux, if it work on your platform
- * and one want to enable it, send me the defined(foobar) needed
- */
-#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
-	    const char *h_err_txt = "";
-
-	    switch (h_errno) {
-		case HOST_NOT_FOUND:
-		    h_err_txt = "Authoritive host not found";
-		    break;
-
-		case TRY_AGAIN:
-		    h_err_txt =
-			"Non-authoritive host not found or server failure.";
-		    break;
-
-		case NO_RECOVERY:
-		    h_err_txt =
-			"Non-recoverable errors:  FORMERR, REFUSED, or NOTIMP.";
-		    break;
-
-		case NO_ADDRESS:
-		    h_err_txt =
-			"Valid name, no data record of requested type.";
-		    break;
-
-		default:
-		    h_err_txt = "No error text defined.";
-		    break;
-	    }
-	    __xmlIOErr(XML_FROM_HTTP, 0, h_err_txt);
-#else
-	    __xmlIOErr(XML_FROM_HTTP, 0, "Failed to resolve host");
-#endif
-	    return (-1);
-	}
-
-	for (i = 0; h->h_addr_list[i]; i++) {
-	    if (h->h_addrtype == AF_INET) {
-		/* A records (IPv4) */
-		if ((unsigned int) h->h_length > sizeof(ia)) {
-		    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
-		    return (-1);
-		}
-		memcpy (&ia, h->h_addr_list[i], h->h_length);
-		sockin.sin_family = h->h_addrtype;
-		sockin.sin_addr = ia;
-		sockin.sin_port = (u_short)htons ((unsigned short)port);
-		addr = (struct sockaddr *) &sockin;
-#ifdef SUPPORT_IP6
-	    } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
-		/* AAAA records (IPv6) */
-		if ((unsigned int) h->h_length > sizeof(ia6)) {
-		    __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n");
-		    return (-1);
-		}
-		memcpy (&ia6, h->h_addr_list[i], h->h_length);
-		sockin6.sin6_family = h->h_addrtype;
-		sockin6.sin6_addr = ia6;
-		sockin6.sin6_port = htons (port);
-		addr = (struct sockaddr *) &sockin6;
-#endif
-	    } else
-		break;              /* for */
-
-	    s = xmlNanoHTTPConnectAttempt (addr);
-	    if (s != -1)
-		return (s);
-	}
-    }
-#endif
-
-#ifdef DEBUG_HTTP
-    xmlGenericError(xmlGenericErrorContext,
-                    "xmlNanoHTTPConnectHost:  unable to connect to '%s'.\n",
-                    host);
-#endif
-    return (-1);
-}
-
-
-/**
- * xmlNanoHTTPOpen:
- * @URL:  The URL to load
- * @contentType:  if available the Content-Type information will be
- *                returned at that location
- *
- * This function try to open a connection to the indicated resource
- * via HTTP GET.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- *     The contentType, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPOpen(const char *URL, char **contentType) {
-    if (contentType != NULL) *contentType = NULL;
-    return(xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL, 0));
-}
-
-/**
- * xmlNanoHTTPOpenRedir:
- * @URL:  The URL to load
- * @contentType:  if available the Content-Type information will be
- *                returned at that location
- * @redir: if available the redirected URL will be returned
- *
- * This function try to open a connection to the indicated resource
- * via HTTP GET.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- *     The contentType, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPOpenRedir(const char *URL, char **contentType, char **redir) {
-    if (contentType != NULL) *contentType = NULL;
-    if (redir != NULL) *redir = NULL;
-    return(xmlNanoHTTPMethodRedir(URL, NULL, NULL, contentType, redir, NULL,0));
-}
-
-/**
- * xmlNanoHTTPRead:
- * @ctx:  the HTTP context
- * @dest:  a buffer
- * @len:  the buffer length
- *
- * This function tries to read @len bytes from the existing HTTP connection
- * and saves them in @dest. This is a blocking call.
- *
- * Returns the number of byte read. 0 is an indication of an end of connection.
- *         -1 indicates a parameter error.
- */
-int
-xmlNanoHTTPRead(void *ctx, void *dest, int len) {
-    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-#ifdef HAVE_ZLIB_H
-    int bytes_read = 0;
-    int orig_avail_in;
-    int z_ret;
-#endif
-
-    if (ctx == NULL) return(-1);
-    if (dest == NULL) return(-1);
-    if (len <= 0) return(0);
-
-#ifdef HAVE_ZLIB_H
-    if (ctxt->usesGzip == 1) {
-        if (ctxt->strm == NULL) return(0);
- 
-        ctxt->strm->next_out = dest;
-        ctxt->strm->avail_out = len;
-	ctxt->strm->avail_in = ctxt->inptr - ctxt->inrptr;
-
-        while (ctxt->strm->avail_out > 0 &&
-	       (ctxt->strm->avail_in > 0 || xmlNanoHTTPRecv(ctxt) > 0)) {
-            orig_avail_in = ctxt->strm->avail_in =
-			    ctxt->inptr - ctxt->inrptr - bytes_read;
-            ctxt->strm->next_in = BAD_CAST (ctxt->inrptr + bytes_read);
-
-            z_ret = inflate(ctxt->strm, Z_NO_FLUSH);
-            bytes_read += orig_avail_in - ctxt->strm->avail_in;
-
-            if (z_ret != Z_OK) break;
-	}
-
-        ctxt->inrptr += bytes_read;
-        return(len - ctxt->strm->avail_out);
-    }
-#endif
-
-    while (ctxt->inptr - ctxt->inrptr < len) {
-        if (xmlNanoHTTPRecv(ctxt) <= 0) break;
-    }
-    if (ctxt->inptr - ctxt->inrptr < len)
-        len = ctxt->inptr - ctxt->inrptr;
-    memcpy(dest, ctxt->inrptr, len);
-    ctxt->inrptr += len;
-    return(len);
-}
-
-/**
- * xmlNanoHTTPClose:
- * @ctx:  the HTTP context
- *
- * This function closes an HTTP context, it ends up the connection and
- * free all data related to it.
- */
-void
-xmlNanoHTTPClose(void *ctx) {
-    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-
-    if (ctx == NULL) return;
-
-    xmlNanoHTTPFreeCtxt(ctxt);
-}
-
-/**
- * xmlNanoHTTPMethodRedir:
- * @URL:  The URL to load
- * @method:  the HTTP method to use
- * @input:  the input string if any
- * @contentType:  the Content-Type information IN and OUT
- * @redir:  the redirected URL OUT
- * @headers:  the extra headers
- * @ilen:  input length
- *
- * This function try to open a connection to the indicated resource
- * via HTTP using the given @method, adding the given extra headers
- * and the input buffer for the request content.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- *     The contentType, or redir, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input,
-                  char **contentType, char **redir,
-		  const char *headers, int ilen ) {
-    xmlNanoHTTPCtxtPtr ctxt;
-    char *bp, *p;
-    int blen, ret;
-    int nbRedirects = 0;
-    char *redirURL = NULL;
-#ifdef DEBUG_HTTP
-    int xmt_bytes;
-#endif
-    
-    if (URL == NULL) return(NULL);
-    if (method == NULL) method = "GET";
-    xmlNanoHTTPInit();
-
-retry:
-    if (redirURL == NULL)
-	ctxt = xmlNanoHTTPNewCtxt(URL);
-    else {
-	ctxt = xmlNanoHTTPNewCtxt(redirURL);
-	ctxt->location = xmlMemStrdup(redirURL);
-    }
-
-    if ( ctxt == NULL ) {
-	return ( NULL );
-    }
-
-    if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
-	__xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
-        xmlNanoHTTPFreeCtxt(ctxt);
-	if (redirURL != NULL) xmlFree(redirURL);
-        return(NULL);
-    }
-    if (ctxt->hostname == NULL) {
-	__xmlIOErr(XML_FROM_HTTP, XML_HTTP_UNKNOWN_HOST,
-	           "Failed to identify host in URI");
-        xmlNanoHTTPFreeCtxt(ctxt);
-	if (redirURL != NULL) xmlFree(redirURL);
-        return(NULL);
-    }
-    if (proxy) {
-	blen = strlen(ctxt->hostname) * 2 + 16;
-	ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
-    }
-    else {
-	blen = strlen(ctxt->hostname);
-	ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
-    }
-    if (ret < 0) {
-        xmlNanoHTTPFreeCtxt(ctxt);
-	if (redirURL != NULL) xmlFree(redirURL);
-        return(NULL);
-    }
-    ctxt->fd = ret;
-
-    if (input == NULL)
-	ilen = 0;
-    else
-	blen += 36;
-
-    if (headers != NULL)
-	blen += strlen(headers) + 2;
-    if (contentType && *contentType)
-	/* reserve for string plus 'Content-Type: \r\n" */
-	blen += strlen(*contentType) + 16;
-    if (ctxt->query != NULL)
-	/* 1 for '?' */
-	blen += strlen(ctxt->query) + 1;
-    blen += strlen(method) + strlen(ctxt->path) + 24;
-#ifdef HAVE_ZLIB_H
-    /* reserve for possible 'Accept-Encoding: gzip' string */
-    blen += 23;
-#endif
-    if (ctxt->port != 80) {
-	/* reserve space for ':xxxxx', incl. potential proxy */
-	if (proxy)
-	    blen += 12;
-	else
-	    blen += 6;
-    }
-    bp = (char*)xmlMallocAtomic(blen);
-    if ( bp == NULL ) {
-        xmlNanoHTTPFreeCtxt( ctxt );
-	xmlHTTPErrMemory("allocating header buffer");
-	return ( NULL );
-    }
-
-    p = bp;
-
-    if (proxy) {
-	if (ctxt->port != 80) {
-	    p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", 
-			method, ctxt->hostname,
-		 	ctxt->port, ctxt->path );
-	}
-	else 
-	    p += snprintf( p, blen - (p - bp), "%s http://%s%s", method,
-	    		ctxt->hostname, ctxt->path);
-    }
-    else
-	p += snprintf( p, blen - (p - bp), "%s %s", method, ctxt->path);
-
-    if (ctxt->query != NULL)
-	p += snprintf( p, blen - (p - bp), "?%s", ctxt->query);
-
-    if (ctxt->port == 80) {
-        p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s\r\n", 
-		    ctxt->hostname);
-    } else {
-        p += snprintf( p, blen - (p - bp), " HTTP/1.0\r\nHost: %s:%d\r\n",
-		    ctxt->hostname, ctxt->port);
-    }
-
-#ifdef HAVE_ZLIB_H
-    p += snprintf(p, blen - (p - bp), "Accept-Encoding: gzip\r\n");
-#endif
-
-    if (contentType != NULL && *contentType) 
-	p += snprintf(p, blen - (p - bp), "Content-Type: %s\r\n", *contentType);
-
-    if (headers != NULL)
-	p += snprintf( p, blen - (p - bp), "%s", headers );
-
-    if (input != NULL)
-	snprintf(p, blen - (p - bp), "Content-Length: %d\r\n\r\n", ilen );
-    else
-	snprintf(p, blen - (p - bp), "\r\n");
-
-#ifdef DEBUG_HTTP
-    xmlGenericError(xmlGenericErrorContext,
-	    "-> %s%s", proxy? "(Proxy) " : "", bp);
-    if ((blen -= strlen(bp)+1) < 0)
-	xmlGenericError(xmlGenericErrorContext,
-		"ERROR: overflowed buffer by %d bytes\n", -blen);
-#endif
-    ctxt->outptr = ctxt->out = bp;
-    ctxt->state = XML_NANO_HTTP_WRITE;
-    blen = strlen( ctxt->out );
-#ifdef DEBUG_HTTP
-    xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen );
-    if ( xmt_bytes != blen )
-        xmlGenericError( xmlGenericErrorContext,
-			"xmlNanoHTTPMethodRedir:  Only %d of %d %s %s\n",
-			xmt_bytes, blen,
-			"bytes of HTTP headers sent to host",
-			ctxt->hostname );
-#else
-    xmlNanoHTTPSend(ctxt, ctxt->out, blen );
-#endif
-
-    if ( input != NULL ) {
-#ifdef DEBUG_HTTP
-        xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen );
-
-	if ( xmt_bytes != ilen )
-	    xmlGenericError( xmlGenericErrorContext,
-	    		"xmlNanoHTTPMethodRedir:  Only %d of %d %s %s\n",
-			xmt_bytes, ilen,
-			"bytes of HTTP content sent to host",
-			ctxt->hostname );
-#else
-	xmlNanoHTTPSend( ctxt, input, ilen );
-#endif
-    }
-
-    ctxt->state = XML_NANO_HTTP_READ;
-
-    while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
-        if (*p == 0) {
-	    ctxt->content = ctxt->inrptr;
-	    xmlFree(p);
-	    break;
-	}
-	xmlNanoHTTPScanAnswer(ctxt, p);
-
-#ifdef DEBUG_HTTP
-	xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
-#endif
-        xmlFree(p);
-    }
-
-    if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
-        (ctxt->returnValue < 400)) {
-#ifdef DEBUG_HTTP
-	xmlGenericError(xmlGenericErrorContext,
-		"\nRedirect to: %s\n", ctxt->location);
-#endif
-	while ( xmlNanoHTTPRecv(ctxt) > 0 ) ;
-        if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
-	    nbRedirects++;
-	    if (redirURL != NULL)
-		xmlFree(redirURL);
-	    redirURL = xmlMemStrdup(ctxt->location);
-	    xmlNanoHTTPFreeCtxt(ctxt);
-	    goto retry;
-	}
-	xmlNanoHTTPFreeCtxt(ctxt);
-	if (redirURL != NULL) xmlFree(redirURL);
-#ifdef DEBUG_HTTP
-	xmlGenericError(xmlGenericErrorContext,
-		"xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n");
-#endif
-	return(NULL);
-    }
-
-    if (contentType != NULL) {
-	if (ctxt->contentType != NULL)
-	    *contentType = xmlMemStrdup(ctxt->contentType);
-	else
-	    *contentType = NULL;
-    }
-
-    if ((redir != NULL) && (redirURL != NULL)) {
-	*redir = redirURL;
-    } else {
-	if (redirURL != NULL)
-	    xmlFree(redirURL);
-	if (redir != NULL)
-	    *redir = NULL;
-    }
-
-#ifdef DEBUG_HTTP
-    if (ctxt->contentType != NULL)
-	xmlGenericError(xmlGenericErrorContext,
-		"\nCode %d, content-type '%s'\n\n",
-	       ctxt->returnValue, ctxt->contentType);
-    else
-	xmlGenericError(xmlGenericErrorContext,
-		"\nCode %d, no content-type\n\n",
-	       ctxt->returnValue);
-#endif
-
-    return((void *) ctxt);
-}
-
-/**
- * xmlNanoHTTPMethod:
- * @URL:  The URL to load
- * @method:  the HTTP method to use
- * @input:  the input string if any
- * @contentType:  the Content-Type information IN and OUT
- * @headers:  the extra headers
- * @ilen:  input length
- *
- * This function try to open a connection to the indicated resource
- * via HTTP using the given @method, adding the given extra headers
- * and the input buffer for the request content.
- *
- * Returns NULL in case of failure, otherwise a request handler.
- *     The contentType, if provided must be freed by the caller
- */
-
-void*
-xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
-                  char **contentType, const char *headers, int ilen) {
-    return(xmlNanoHTTPMethodRedir(URL, method, input, contentType,
-		                  NULL, headers, ilen));
-}
-
-/**
- * xmlNanoHTTPFetch:
- * @URL:  The URL to load
- * @filename:  the filename where the content should be saved
- * @contentType:  if available the Content-Type information will be
- *                returned at that location
- *
- * This function try to fetch the indicated resource via HTTP GET
- * and save it's content in the file.
- *
- * Returns -1 in case of failure, 0 incase of success. The contentType,
- *     if provided must be freed by the caller
- */
-int
-xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
-    void *ctxt = NULL;
-    char *buf = NULL;
-    int fd;
-    int len;
-    
-    if (filename == NULL) return(-1);
-    ctxt = xmlNanoHTTPOpen(URL, contentType);
-    if (ctxt == NULL) return(-1);
-
-    if (!strcmp(filename, "-")) 
-        fd = 0;
-    else {
-        fd = open(filename, O_CREAT | O_WRONLY, 00644);
-	if (fd < 0) {
-	    xmlNanoHTTPClose(ctxt);
-	    if ((contentType != NULL) && (*contentType != NULL)) {
-	        xmlFree(*contentType);
-		*contentType = NULL;
-	    }
-	    return(-1);
-	}
-    }
-
-    xmlNanoHTTPFetchContent( ctxt, &buf, &len );
-    if ( len > 0 ) {
-	write(fd, buf, len);
-    }
-
-    xmlNanoHTTPClose(ctxt);
-    close(fd);
-    return(0);
-}
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlNanoHTTPSave:
- * @ctxt:  the HTTP context
- * @filename:  the filename where the content should be saved
- *
- * This function saves the output of the HTTP transaction to a file
- * It closes and free the context at the end
- *
- * Returns -1 in case of failure, 0 incase of success.
- */
-int
-xmlNanoHTTPSave(void *ctxt, const char *filename) {
-    char *buf = NULL;
-    int fd;
-    int len;
-    
-    if ((ctxt == NULL) || (filename == NULL)) return(-1);
-
-    if (!strcmp(filename, "-")) 
-        fd = 0;
-    else {
-        fd = open(filename, O_CREAT | O_WRONLY, 0666);
-	if (fd < 0) {
-	    xmlNanoHTTPClose(ctxt);
-	    return(-1);
-	}
-    }
-
-    xmlNanoHTTPFetchContent( ctxt, &buf, &len );
-    if ( len > 0 ) {
-	write(fd, buf, len);
-    }
-
-    xmlNanoHTTPClose(ctxt);
-    close(fd);
-    return(0);
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
-/**
- * xmlNanoHTTPReturnCode:
- * @ctx:  the HTTP context
- *
- * Get the latest HTTP return code received
- *
- * Returns the HTTP return code for the request.
- */
-int
-xmlNanoHTTPReturnCode(void *ctx) {
-    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-
-    if (ctxt == NULL) return(-1);
-
-    return(ctxt->returnValue);
-}
-
-/**
- * xmlNanoHTTPAuthHeader:
- * @ctx:  the HTTP context
- *
- * Get the authentication header of an HTTP context
- *
- * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
- * header.
- */
-const char *
-xmlNanoHTTPAuthHeader(void *ctx) {
-    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
-
-    if (ctxt == NULL) return(NULL);
-
-    return(ctxt->authHeader);
-}
-
-/**
- * xmlNanoHTTPContentLength:
- * @ctx:  the HTTP context
- *
- * Provides the specified content length from the HTTP header.
- *
- * Return the specified content length from the HTTP header.  Note that
- * a value of -1 indicates that the content length element was not included in
- * the response header.
- */
-int
-xmlNanoHTTPContentLength( void * ctx ) {
-    xmlNanoHTTPCtxtPtr	ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
-    return ( ( ctxt == NULL ) ? -1 : ctxt->ContentLength );
-}
-
-/**
- * xmlNanoHTTPRedir:
- * @ctx:  the HTTP context
- *
- * Provides the specified redirection URL if available from the HTTP header.
- *
- * Return the specified redirection URL or NULL if not redirected.
- */
-const char *
-xmlNanoHTTPRedir( void * ctx ) {
-    xmlNanoHTTPCtxtPtr	ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
-    return ( ( ctxt == NULL ) ? NULL : ctxt->location );
-}
-
-/**
- * xmlNanoHTTPEncoding:
- * @ctx:  the HTTP context
- *
- * Provides the specified encoding if specified in the HTTP headers.
- *
- * Return the specified encoding or NULL if not available
- */
-const char *
-xmlNanoHTTPEncoding( void * ctx ) {
-    xmlNanoHTTPCtxtPtr	ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
-    return ( ( ctxt == NULL ) ? NULL : ctxt->encoding );
-}
-
-/**
- * xmlNanoHTTPMimeType:
- * @ctx:  the HTTP context
- *
- * Provides the specified Mime-Type if specified in the HTTP headers.
- *
- * Return the specified Mime-Type or NULL if not available
- */
-const char *
-xmlNanoHTTPMimeType( void * ctx ) {
-    xmlNanoHTTPCtxtPtr	ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
-    return ( ( ctxt == NULL ) ? NULL : ctxt->mimeType );
-}
-
-/**
- * xmlNanoHTTPFetchContent:
- * @ctx:  the HTTP context
- * @ptr:  pointer to set to the content buffer.
- * @len:  integer pointer to hold the length of the content
- *
- * Check if all the content was read
- *
- * Returns 0 if all the content was read and available, returns
- * -1 if received content length was less than specified or an error 
- * occurred.
- */
-static int
-xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ) {
-    xmlNanoHTTPCtxtPtr	ctxt = (xmlNanoHTTPCtxtPtr)ctx;
-
-    int			rc = 0;
-    int			cur_lgth;
-    int			rcvd_lgth;
-    int			dummy_int;
-    char *		dummy_ptr = NULL;
-
-    /*  Dummy up return input parameters if not provided  */
-
-    if ( len == NULL )
-        len = &dummy_int;
-
-    if ( ptr == NULL )
-        ptr = &dummy_ptr;
-
-    /*  But can't work without the context pointer  */
-
-    if ( ( ctxt == NULL ) || ( ctxt->content == NULL ) ) {
-        *len = 0;
-	*ptr = NULL;
-	return ( -1 );
-    }
-
-    rcvd_lgth = ctxt->inptr - ctxt->content;
-
-    while ( (cur_lgth = xmlNanoHTTPRecv( ctxt )) > 0 ) {
-
-	rcvd_lgth += cur_lgth;
-	if ( (ctxt->ContentLength > 0) && (rcvd_lgth >= ctxt->ContentLength) )
-	    break;
-    }
-
-    *ptr = ctxt->content;
-    *len = rcvd_lgth;
-
-    if ( ( ctxt->ContentLength > 0 ) && ( rcvd_lgth < ctxt->ContentLength ) )
-        rc = -1;
-    else if ( rcvd_lgth == 0 )
-	rc = -1;
-
-    return ( rc );
-}
-
-#ifdef STANDALONE
-int main(int argc, char **argv) {
-    char *contentType = NULL;
-
-    if (argv[1] != NULL) {
-	if (argv[2] != NULL) 
-	    xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
-        else
-	    xmlNanoHTTPFetch(argv[1], "-", &contentType);
-	if (contentType != NULL) xmlFree(contentType);
-    } else {
-        xmlGenericError(xmlGenericErrorContext,
-		"%s: minimal HTTP GET implementation\n", argv[0]);
-        xmlGenericError(xmlGenericErrorContext,
-		"\tusage %s [ URL [ filename ] ]\n", argv[0]);
-    }
-    xmlNanoHTTPCleanup();
-    xmlMemoryDump();
-    return(0);
-}
-#endif /* STANDALONE */
-#else /* !LIBXML_HTTP_ENABLED */
-#ifdef STANDALONE
-#include <stdio.h>
-int main(int argc, char **argv) {
-    xmlGenericError(xmlGenericErrorContext,
-	    "%s : HTTP support not compiled in\n", argv[0]);
-    return(0);
-}
-#endif /* STANDALONE */
-#endif /* LIBXML_HTTP_ENABLED */
-#define bottom_nanohttp
-#include "elfgcchack.h"
diff --git a/third_party/libxml/src/xmlIO.c b/third_party/libxml/src/xmlIO.c
index 8fc00e3..29623dc 100644
--- a/third_party/libxml/src/xmlIO.c
+++ b/third_party/libxml/src/xmlIO.c
@@ -85,8 +85,6 @@
 #include <libxml/parserInternals.h>
 #include <libxml/xmlIO.h>
 #include <libxml/uri.h>
-#include <libxml/nanohttp.h>
-#include <libxml/nanoftp.h>
 #include <libxml/xmlerror.h>
 #ifdef LIBXML_CATALOG_ENABLED
 #include <libxml/catalog.h>
diff --git a/third_party/libxml/win32/include/libxml/xmlversion.h b/third_party/libxml/win32/include/libxml/xmlversion.h
index 3753baf..90f38d5 100644
--- a/third_party/libxml/win32/include/libxml/xmlversion.h
+++ b/third_party/libxml/win32/include/libxml/xmlversion.h
@@ -165,7 +165,7 @@
  *
  * Whether the FTP support is configured in
  */
-#if 1
+#if 0
 #define LIBXML_FTP_ENABLED
 #endif
 
@@ -174,7 +174,7 @@
  *
  * Whether the HTTP support is configured in
  */
-#if 1
+#if 0
 #define LIBXML_HTTP_ENABLED
 #endif
 
diff --git a/third_party/re2/patches/re2-libcxx.patch b/third_party/re2/patches/re2-libcxx.patch
index fc4dd1c..54f3b6b 100644
--- a/third_party/re2/patches/re2-libcxx.patch
+++ b/third_party/re2/patches/re2-libcxx.patch
@@ -12,3 +12,12 @@
  
  #include <tr1/unordered_set>
  using std::tr1::unordered_set;
+@@ -54,1 +55,1 @@ using std::tr1::unordered_set;
+ #else
+
+ #include <unordered_set>
+-#if defined(WIN32) || defined(OS_ANDROID)
++#if defined(WIN32) || (defined(OS_ANDROID) && !defined(_LIBCPP_ABI_VERSION))
+ using std::tr1::unordered_set;
+ #else
+ using std::unordered_set;
\ No newline at end of file
diff --git a/third_party/re2/util/util.h b/third_party/re2/util/util.h
index 8350445..4f0fdb8 100644
--- a/third_party/re2/util/util.h
+++ b/third_party/re2/util/util.h
@@ -55,7 +55,7 @@
 #else
 
 #include <unordered_set>
-#if defined(WIN32) || defined(OS_ANDROID)
+#if defined(WIN32) || (defined(OS_ANDROID) && !defined(_LIBCPP_ABI_VERSION))
 using std::tr1::unordered_set;
 #else
 using std::unordered_set;
diff --git a/tools/android/md5sum/md5sum.cc b/tools/android/md5sum/md5sum.cc
index 07ce2c2..a204569 100644
--- a/tools/android/md5sum/md5sum.cc
+++ b/tools/android/md5sum/md5sum.cc
@@ -18,25 +18,21 @@
 
 namespace {
 
-const int kBufferSize = 1024;
-
 // Returns whether |path|'s MD5 was successfully written to |digest_string|.
 bool MD5Sum(const char* path, std::string* digest_string) {
-  std::ifstream stream(path);
-  if (!stream.good()) {
+  base::ScopedFILE file(fopen(path, "rb"));
+  if (!file) {
     LOG(ERROR) << "Could not open file " << path;
     return false;
   }
   base::MD5Context ctx;
   base::MD5Init(&ctx);
-  char buf[kBufferSize];
-  while (stream.good()) {
-    std::streamsize bytes_read = stream.readsome(buf, sizeof(buf));
-    if (bytes_read == 0)
-      break;
-    base::MD5Update(&ctx, base::StringPiece(buf, bytes_read));
-  }
-  if (stream.fail()) {
+  const size_t kBufferSize = 1 << 16;
+  scoped_ptr<char[]> buf(new char[kBufferSize]);
+  size_t len;
+  while ((len = fread(buf.get(), 1, kBufferSize, file.get())) > 0)
+    base::MD5Update(&ctx, base::StringPiece(buf.get(), len));
+  if (ferror(file.get())) {
     LOG(ERROR) << "Error reading file " << path;
     return false;
   }
diff --git a/tools/android/run_pie/run_pie.gyp b/tools/android/run_pie/run_pie.gyp
index b713dc4..75850f4 100644
--- a/tools/android/run_pie/run_pie.gyp
+++ b/tools/android/run_pie/run_pie.gyp
@@ -18,10 +18,10 @@
       'ldflags!': [
         '-pie',
       ],
-      # Don't inherit unneeded dependencies on stlport.so, so the binary remains
+      # Don't inherit unneeded dependencies on libc++, so the binary remains
       # self-contained also in component=shared_library builds.
       'libraries!': [
-        '-l<(android_stlport_library)',
+        '-l<(android_libcpp_library)',
       ],
     },
     {
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp
index 931da02..6a4233a 100644
--- a/tools/clang/plugins/ChromeClassTester.cpp
+++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -18,6 +18,7 @@
 #endif
 
 using namespace clang;
+using chrome_checker::Options;
 
 namespace {
 
@@ -30,8 +31,10 @@
 
 }  // namespace
 
-ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
-    : instance_(instance),
+ChromeClassTester::ChromeClassTester(CompilerInstance& instance,
+                                     const Options& options)
+    : options_(options),
+      instance_(instance),
       diagnostic_(instance.getDiagnostics()) {
   BuildBannedLists();
 }
@@ -95,16 +98,13 @@
   std::string err;
   err = "[chromium-style] ";
   err += raw_error;
-  // TODO(dcheng): Re-enable -Werror for these diagnostics on Windows once all
-  // the pre-existing warnings are cleaned up. https://crbug.com/467287
-  DiagnosticIDs::Level level =
-#if !defined(LLVM_ON_WIN32)
-      diagnostic().getWarningsAsErrors() ?
-      DiagnosticIDs::Error :
-#endif
-      DiagnosticIDs::Warning;
+
+  DiagnosticIDs::Level level = getErrorLevel() == DiagnosticsEngine::Error
+      ? DiagnosticIDs::Error : DiagnosticIDs::Warning;
+
   unsigned id = diagnostic().getDiagnosticIDs()->getCustomDiagID(level, err);
   DiagnosticBuilder builder = diagnostic().Report(full, id);
+
 }
 
 bool ChromeClassTester::InBannedDirectory(SourceLocation loc) {
@@ -130,9 +130,7 @@
   }
 
 #if defined(LLVM_ON_UNIX)
-  // We need to munge the paths so that they are relative to the repository
-  // srcroot. We first resolve the symlinktastic relative path and then
-  // remove our known srcroot from it if needed.
+  // Resolve the symlinktastic relative path and make it absolute.
   char resolvedPath[MAXPATHLEN];
   if (realpath(filename.c_str(), resolvedPath)) {
     filename = resolvedPath;
@@ -141,6 +139,15 @@
 
 #if defined(LLVM_ON_WIN32)
   std::replace(filename.begin(), filename.end(), '\\', '/');
+
+  // On Posix, realpath() has made the path absolute.  On Windows, this isn't
+  // necessarily true, so prepend a '/' to the path to make sure the
+  // banned_directories_ loop below works correctly.
+  // This turns e.g. "gen/dir/file.cc" to "/gen/dir/file.cc" which lets the
+  // "/gen/" banned_dir work.
+  // This seems simpler than converting to utf16, calling GetFullPathNameW(),
+  // and converting back to utf8.
+  filename.insert(filename.begin(), '/');
 #endif
 
   for (const std::string& banned_dir : banned_directories_) {
@@ -304,3 +311,11 @@
   *filename = ploc.getFilename();
   return true;
 }
+
+DiagnosticsEngine::Level ChromeClassTester::getErrorLevel() {
+  if (options_.warn_only)
+    return DiagnosticsEngine::Warning;
+
+  return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
+                                            : DiagnosticsEngine::Warning;
+}
diff --git a/tools/clang/plugins/ChromeClassTester.h b/tools/clang/plugins/ChromeClassTester.h
index ed65050..6b5cdf3 100644
--- a/tools/clang/plugins/ChromeClassTester.h
+++ b/tools/clang/plugins/ChromeClassTester.h
@@ -8,6 +8,7 @@
 #include <set>
 #include <vector>
 
+#include "Options.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Frontend/CompilerInstance.h"
@@ -16,7 +17,8 @@
 // headers to subclasses which implement CheckChromeClass().
 class ChromeClassTester : public clang::ASTConsumer {
  public:
-  explicit ChromeClassTester(clang::CompilerInstance& instance);
+  ChromeClassTester(clang::CompilerInstance& instance,
+                    const chrome_checker::Options& options);
   virtual ~ChromeClassTester();
 
   // clang::ASTConsumer:
@@ -25,6 +27,8 @@
 
   void CheckTag(clang::TagDecl*);
 
+  clang::DiagnosticsEngine::Level getErrorLevel();
+
  protected:
   clang::CompilerInstance& instance() { return instance_; }
   clang::DiagnosticsEngine& diagnostic() { return diagnostic_; }
@@ -50,6 +54,9 @@
   // implementation (.cc, .cpp, .mm) file.
   bool InImplementationFile(clang::SourceLocation location);
 
+  // Options.
+  const chrome_checker::Options options_;
+
  private:
   void BuildBannedLists();
 
diff --git a/tools/clang/plugins/FindBadConstructsAction.cpp b/tools/clang/plugins/FindBadConstructsAction.cpp
index 6c39d72..8125084 100644
--- a/tools/clang/plugins/FindBadConstructsAction.cpp
+++ b/tools/clang/plugins/FindBadConstructsAction.cpp
@@ -57,6 +57,8 @@
       options_.with_ast_visitor = true;
     } else if (args[i] == "check-templates") {
       options_.check_templates = true;
+    } else if (args[i] == "warn-only") {
+      options_.warn_only = true;
     } else {
       parsed = false;
       llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n";
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.cpp b/tools/clang/plugins/FindBadConstructsConsumer.cpp
index 20919a4..4dc305e 100644
--- a/tools/clang/plugins/FindBadConstructsConsumer.cpp
+++ b/tools/clang/plugins/FindBadConstructsConsumer.cpp
@@ -101,7 +101,7 @@
 
 FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance,
                                                      const Options& options)
-    : ChromeClassTester(instance), options_(options) {
+    : ChromeClassTester(instance, options) {
   // Messages for virtual method specifiers.
   diag_method_requires_override_ =
       diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresOverride);
@@ -593,19 +593,6 @@
   return None;
 }
 
-// Adds either a warning or error, based on the current handling of
-// -Werror.
-DiagnosticsEngine::Level FindBadConstructsConsumer::getErrorLevel() {
-#if defined(LLVM_ON_WIN32)
-  // TODO(dcheng): Re-enable -Werror for these diagnostics on Windows once all
-  // the pre-existing warnings are cleaned up. https://crbug.com/467287
-  return DiagnosticsEngine::Warning;
-#else
-  return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
-                                            : DiagnosticsEngine::Warning;
-#endif
-}
-
 // Returns true if |base| specifies one of the Chromium reference counted
 // classes (base::RefCounted / base::RefCountedThreadSafe).
 bool FindBadConstructsConsumer::IsRefCountedCallback(
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.h b/tools/clang/plugins/FindBadConstructsConsumer.h
index 6e2b2c9..c52a8f3 100644
--- a/tools/clang/plugins/FindBadConstructsConsumer.h
+++ b/tools/clang/plugins/FindBadConstructsConsumer.h
@@ -71,7 +71,6 @@
   static RefcountIssue CheckRecordForRefcountIssue(
       const clang::CXXRecordDecl* record,
       clang::SourceLocation& loc);
-  clang::DiagnosticsEngine::Level getErrorLevel();
   static bool IsRefCountedCallback(const clang::CXXBaseSpecifier* base,
                                    clang::CXXBasePath& path,
                                    void* user_data);
@@ -86,8 +85,6 @@
   void CheckWeakPtrFactoryMembers(clang::SourceLocation record_location,
                                   clang::CXXRecordDecl* record);
 
-  const Options options_;
-
   unsigned diag_method_requires_override_;
   unsigned diag_redundant_virtual_specifier_;
   unsigned diag_base_method_virtual_and_final_;
diff --git a/tools/clang/plugins/Options.h b/tools/clang/plugins/Options.h
index 112ec10..5131905 100644
--- a/tools/clang/plugins/Options.h
+++ b/tools/clang/plugins/Options.h
@@ -12,12 +12,14 @@
       : check_base_classes(false),
         check_enum_last_value(false),
         with_ast_visitor(false),
-        check_templates(false) {}
+        check_templates(false),
+        warn_only(false) {}
 
   bool check_base_classes;
   bool check_enum_last_value;
   bool with_ast_visitor;
   bool check_templates;
+  bool warn_only;
 };
 
 }  // namespace chrome_checker
diff --git a/tools/clang/plugins/tests/warn_only.cpp b/tools/clang/plugins/tests/warn_only.cpp
new file mode 100644
index 0000000..1fbefcb
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.cpp
@@ -0,0 +1,5 @@
+// Copyright (c) 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 "warn_only.h"
diff --git a/tools/clang/plugins/tests/warn_only.flags b/tools/clang/plugins/tests/warn_only.flags
new file mode 100644
index 0000000..01e7b3b
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.flags
@@ -0,0 +1 @@
+-Werror -Xclang -plugin-arg-find-bad-constructs -Xclang warn-only
diff --git a/tools/clang/plugins/tests/warn_only.h b/tools/clang/plugins/tests/warn_only.h
new file mode 100644
index 0000000..fcc0aa1
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.h
@@ -0,0 +1,21 @@
+// Copyright (c) 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 WARN_ONLY_H_
+#define WARN_ONLY_H_
+
+#include <string>
+#include <vector>
+
+class InlineCtors {
+ public:
+  InlineCtors() {}
+  ~InlineCtors() {}
+
+ private:
+  std::vector<int> one_;
+  std::vector<std::string> two_;
+};
+
+#endif  // WARN_ONLY_H_
diff --git a/tools/clang/plugins/tests/warn_only.txt b/tools/clang/plugins/tests/warn_only.txt
new file mode 100644
index 0000000..4b5c2d0
--- /dev/null
+++ b/tools/clang/plugins/tests/warn_only.txt
@@ -0,0 +1,8 @@
+In file included from warn_only.cpp:5:
+./warn_only.h:13:3: warning: [chromium-style] Complex constructor has an inlined body.
+  InlineCtors() {}
+  ^
+./warn_only.h:14:3: warning: [chromium-style] Complex destructor has an inline body.
+  ~InlineCtors() {}
+  ^
+2 warnings generated.
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 30d9ce9..9bb306d 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -25,7 +25,7 @@
 # in bringup. Use a pinned revision to make it slightly more stable.
 if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and
     not 'LLVM_FORCE_HEAD_REVISION' in os.environ):
-  LLVM_WIN_REVISION = '235793'
+  LLVM_WIN_REVISION = '235968'
 
 # Path constants. (All of these should be absolute paths.)
 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
index f0dbeb0..dd6f089 100755
--- a/tools/clang/scripts/update.sh
+++ b/tools/clang/scripts/update.sh
@@ -665,7 +665,7 @@
       --platform=android-14 \
       --install-dir="${LLVM_BUILD_DIR}/android-toolchain" \
       --system=linux-x86_64 \
-      --stl=stlport \
+      --stl=libcxx \
       --toolchain=arm-linux-androideabi-4.9
 
   # Android NDK r9d copies a broken unwind.h into the toolchain, see
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index d56ba05..6c353d2 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -218,6 +218,9 @@
   "ui/file_manager/file_manager_resources.grd": {
     "includes": [28100],
   },
+  "components/chrome_apps/chrome_apps_resources.grd": {
+    "includes": [28250],
+  },
   "ui/login/login_resources.grd": {
     "includes": [28300],
   },
diff --git a/tools/valgrind/OWNERS b/tools/valgrind/OWNERS
index 73ce47c..e1a653b 100644
--- a/tools/valgrind/OWNERS
+++ b/tools/valgrind/OWNERS
@@ -2,4 +2,3 @@
 bruening@chromium.org
 glider@chromium.org
 thestig@chromium.org
-timurrrr@chromium.org
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index e8074f3..571beb1 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -401,6 +401,9 @@
   def TestMessageCenter(self):
     return self.SimpleTest("message_center", "message_center_unittests")
 
+  def TestMidi(self):
+    return self.SimpleTest("chrome", "midi_unittests")
+
   def TestMojoCommon(self):
     return self.SimpleTest("mojo_common", "mojo_common_unittests")
 
@@ -696,6 +699,7 @@
     "media": TestMedia,          "media_unittests": TestMedia,
     "message_center": TestMessageCenter,
     "message_center_unittests" : TestMessageCenter,
+    "midi": TestMidi,             "midi_unittests": TestMidi,
     "mojo_common": TestMojoCommon,
     "mojo_system": TestMojoSystem,
     "mojo_public_system": TestMojoPublicSystem,
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index e54404b..ec87454 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -774,3 +774,29 @@
 *!cc::LayerTreeHost::BeginMainFrame
 *!cc::ThreadProxy::BeginMainFrame
 *!base::internal::InvokeHelper<>::MakeItSo
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/483305
+blink_web.dll!blink::WebFrameWidgetImpl::suppressInvalidations
+blink_web.dll!blink::WebFrameWidgetImpl::setRootGraphicsLayer
+blink_web.dll!blink::ChromeClientImpl::attachRootGraphicsLayer
+blink_web.dll!blink::DeprecatedPaintLayerCompositor::detachRootLayer
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/483305b
+blink_web.dll!blink::WebFrameWidgetImpl::setRootGraphicsLayer
+blink_web.dll!blink::ChromeClientImpl::attachRootGraphicsLayer
+blink_web.dll!blink::DeprecatedPaintLayerCompositor::detachRootLayer
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/484352
+blink_web.dll!blink::WebFrameWidgetImpl::setIsAcceleratedCompositingActive
+blink_web.dll!blink::WebFrameWidgetImpl::willCloseLayerTreeView
+scheduler.dll!scheduler::TaskQueueManager::ProcessTaskFromWorkQueue
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/484352b
+blink_web.dll!blink::WebFrameWidgetImpl::setIsAcceleratedCompositingActive
+blink_web.dll!blink::WebFrameWidgetImpl::setRootGraphicsLayer
+blink_web.dll!blink::ChromeClientImpl::attachRootGraphicsLayer
+blink_web.dll!blink::DeprecatedPaintLayerCompositor::detachRootLayer
diff --git a/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt
index ec243c5..82f3f9c 100644
--- a/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/base_unittests.gtest-drmemory_win32.txt
@@ -37,4 +37,4 @@
 MessageLoopTestTypeUI.RecursiveDenial3
 
 # https://crbug.com/481231
-WinHeapDumpProviderTest.DumpInto
+WinHeapDumpProviderTest.OnMemoryDump
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
index b5e2b57..69db506 100644
--- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
@@ -9,9 +9,6 @@
 # http://crbug.com/450221
 ProfileChooserViewExtensionsTest.LockProfileNoBlockOtherProfileExtensions
 
-# http://crbug.com/467514
-AsyncExtensionSettingsWebUITest.testErrorListButtonVisibility
-
 # it takes too long to run all browser_tests with Dr.Memory,
 # and we only select subset to run
 # A*
diff --git a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
index 55df649..cb3deed 100644
--- a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
+++ b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory.txt
@@ -39,3 +39,9 @@
 
 # http://crbug.com/470507
 SRC_ClearKey/EncryptedMediaTest.Playback_VideoClearAudio_WebM/0
+
+# http://crbug.com/484351
+PluginTest.VerifyPluginWindowRect
+
+# http://crbug.com/484852
+PluginTest.NPObjectIdentity
diff --git a/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt b/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt
index 56bb83c..a986378 100644
--- a/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/message_center_unittests.gtest.txt
@@ -1,3 +1,4 @@
 # Fails http://crbug.com/256911
 MessageCenterImplTest.PopupTimersControllerResetTimer
+MessageCenterImplTest.PopupTimersControllerStartMultipleTimers
 MessageCenterImplTest.PopupTimersControllerStartMultipleTimersPause
diff --git a/tools/valgrind/gtest_exclude/mojo_application_manager_unittests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/mojo_application_manager_unittests.gtest-drmemory.txt
deleted file mode 100644
index bb80765..0000000
--- a/tools/valgrind/gtest_exclude/mojo_application_manager_unittests.gtest-drmemory.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# http://crbug.com/416620
-ApplicationManagerTest.*
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
index a43a673..371ea3f 100644
--- a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
+++ b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
@@ -32,3 +32,6 @@
 
 # http://crbug.com/403533
 ExtensionPathUtilTest.BasicPrettifyPathTest
+
+# http://crbug.com/483642
+MultiUserWindowManagerChromeOSTest.FullUserSwitchAnimationTests
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 56948ef..581dd99 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -511,6 +511,15 @@
    fun:_ZN7content18ManifestParserTest13ParseManifestERKN4base16BasicStringPieceISsEE
    fun:_ZN7content45ManifestParserTest_IconDensityParseRules_Test8TestBodyEv
 }
+{
+   bug_484444
+   Memcheck:Leak
+   fun:_Znw*
+   ...
+   fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPK15MojoAsyncWaiter
+   fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16InterfaceRequestIS1_EEPK15MojoAsyncWaiter
+   fun:_ZN7content19ServiceRegistryImpl4BindEN4mojo16InterfaceRequestINS1_15ServiceProviderEEE
+}
 
 #-----------------------------------------------------------------------
 # 3. Suppressions for real chromium bugs that are not yet fixed.
@@ -946,27 +955,6 @@
    fun:*DownloadFileTest5SetUpEv
 }
 {
-   bug_72544
-   Memcheck:Leak
-   fun:malloc
-   fun:_ZN3WTF10fastMallocEj
-   fun:_ZN3WTF10RefCountedIN7blink14StyleSheetListEEnwEj
-   fun:_ZN5blink14StyleSheetList6createEPNS_8DocumentE
-   fun:_ZN5blink8DocumentC2EPNS_5FrameERKNS_4KURLEbbS5_
-   fun:_ZN5blink12HTMLDocumentC1EPNS_5FrameERKNS_4KURLES5_
-   fun:_ZN5blink12HTMLDocument6createEPNS_5FrameERKNS_4KURLES5_
-   fun:_ZN5blink17DOMImplementation14createDocumentERKN3WTF6StringEPNS_5FrameERKNS_4KURLEb
-   fun:_ZN5blink14DocumentWriter14createDocumentERKNS_4KURLE
-   fun:_ZN5blink14DocumentWriter5beginERKNS_4KURLEbPNS_14SecurityOriginE
-   fun:_ZN5blink11FrameLoader4initEv
-   fun:_ZN5blink5Frame4initEv
-   fun:_ZN5blink12WebFrameImpl21initializeAsMainFrameEPNS_11WebViewImplE
-   fun:_ZN5blink11WebViewImpl19initializeMainFrameEPNS_14WebFrameClientE
-   fun:_ZN10RenderViewC1EP16RenderThreadBaseiiRK19RendererPreferencesRK14WebPreferencesPN4base14RefCountedDataIiEEixRKSbItNS8_20string16_char_traitsESaItEE
-   fun:_ZN10RenderView6CreateEP16RenderThreadBaseiiRK19RendererPreferencesRK14WebPreferencesPN4base14RefCountedDataIiEEixRKSbItNS8_20string16_char_traitsESaItEE
-   fun:_ZN12RenderThread15OnCreateNewViewERK18ViewMsg_New_Params
-}
-{
    bug_72698_a
    Memcheck:Leak
    fun:_Znw*
@@ -1823,16 +1811,6 @@
    fun:ChromeMain
 }
 {
-   bug_164178
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN3net25MultiThreadedCertVerifier6VerifyEPNS_15X509CertificateERKSsiPNS_6CRLSetEPNS_16CertVerifyResultERKN4base8CallbackIFviEEEPPvRKNS_11BoundNetLogE
-   fun:_ZN3net25SingleRequestCertVerifier6VerifyEPNS_15X509CertificateERKSsiPNS_6CRLSetEPNS_16CertVerifyResultERKN4base8CallbackIFviEEERKNS_11BoundNetLogE
-   fun:_ZN3net18SSLClientSocketNSS12DoVerifyCertEi
-   fun:_ZN3net18SSLClientSocketNSS15DoHandshakeLoopEi
-   fun:_ZN3net18SSLClientSocketNSS21OnHandshakeIOCompleteEi
-}
-{
    bug_164179
    Memcheck:Leak
    fun:_Znw*
@@ -2663,7 +2641,7 @@
    bug_364724b
    Memcheck:Uninitialized
    fun:_ZN4base17MD5DigestToBase16ERKNS_9MD5DigestE
-   fun:_ZN7content16WebKitTestRunner17CaptureDumpPixelsERK8SkBitmap
+   fun:_ZN7content15BlinkTestRunner17CaptureDumpPixelsERK8SkBitmap
 }
 {
    bug_364724c
@@ -2680,7 +2658,7 @@
    fun:malloc
    fun:_ZN3WTF10fastMallocEm
    fun:_ZN3WTF10RefCountedIN5blink11ScriptStateEEnwEm
-   fun:_ZN5blink11ScriptState6createEN2v86HandleINS1_7ContextEEEN3WTF10PassRefPtrINS_15DOMWrapperWorldEEE
+   fun:_ZN5blink11ScriptState6createEN2v85LocalINS1_7ContextEEEN3WTF10PassRefPtrINS_15DOMWrapperWorldEEE
    ...
    fun:_ZN3WTF15FunctionWrapperIMN5blink12WorkerThreadEFvvEEclEPS2_
 }
@@ -3121,7 +3099,7 @@
    fun:_ZN2v86Object3SetENS_6HandleINS_5ValueEEES3_
    fun:_ZN18WebCoreTestSupport21injectInternalsObjectEN2v85LocalINS0_7ContextEEE
    fun:_ZN5blink17WebTestingSupport21injectInternalsObjectEPNS_13WebLocalFrameE
-   fun:_ZN7content16WebKitTestRunner20DidClearWindowObjectEPN5blink13WebLocalFrameE
+   fun:_ZN7content15BlinkTestRunner20DidClearWindowObjectEPN5blink13WebLocalFrameE
    fun:_ZN7content14RenderViewImpl20didClearWindowObjectEPN5blink13WebLocalFrameE
    fun:_ZN7content15RenderFrameImpl20didClearWindowObjectEPN5blink13WebLocalFrameE
    fun:_ZThn16_N7content15RenderFrameImpl20didClearWindowObjectEPN5blink13WebLocalFrameE
@@ -3131,7 +3109,7 @@
    fun:_ZN5blink11toV8ContextEPNS_10LocalFrameERNS_15DOMWrapperWorldE
    fun:_ZNK5blink17WebLocalFrameImpl22mainWorldScriptContextEv
    fun:_ZN5blink17WebTestingSupport20resetInternalsObjectEPNS_13WebLocalFrameE
-   fun:_ZN7content16WebKitTestRunner5ResetEv
+   fun:_ZN7content15BlinkTestRunner5ResetEv
    fun:_ZN7content26ShellContentRendererClient17RenderViewCreatedEPNS_10RenderViewE
    fun:_ZN7content14RenderViewImpl10InitializeEPNS_20RenderViewImplParamsE
    fun:_ZN7content14RenderViewImpl6CreateEibRKNS_19RendererPreferencesERKNS_14WebPreferencesEiiilRKSbItN4base20string16_char_traitsESaItEEbbibbiRKN5blink13WebScreenInfoE17AccessibilityMode
@@ -3242,17 +3220,6 @@
    fun:_ZN8app_list4test12_GLOBAL__N_122AppListViewTestContext16RunStartPageTestEv
 }
 {
-   bug_405865
-   Memcheck:Uninitialized
-   fun:_ZNK5blink13InlineFlowBox20computeMaxLogicalTopERf
-   ...
-   fun:_ZNK5blink13RootInlineBox13maxLogicalTopEv
-   fun:_ZN5blinkL22computeUnderlineOffsetENS_21TextUnderlinePositionERKNS_11FontMetricsEPKNS_13InlineTextBoxEf
-   fun:_ZN5blink20InlineTextBoxPainter15paintDecorationEPNS_15GraphicsContextERKNS_10FloatPointENS_14TextDecorationE
-   fun:_ZN5blink20InlineTextBoxPainter5paintERNS_9PaintInfoERKNS_11LayoutPointE
-   fun:_ZN5blink13InlineTextBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-}
-{
    bug_415092
    Memcheck:Leak
    fun:_Znw*
@@ -3276,44 +3243,6 @@
    fun:_ZN7content17BlinkPlatformImpl9DoTimeoutEv
 }
 {
-   bug_417048a
-   Memcheck:Uninitialized
-   ...
-   fun:_ZNK5blink17RenderLineBoxList7hitTestEPNS_20RenderBoxModelObjectERKNS_14HitTestRequestERNS_13HitTestResultERKNS_15HitTestLocationERKNS_11LayoutPointENS_13HitTestActionE
-   fun:_ZN5blink*Render*_14HitTestRequestERNS_13HitTestResultERKNS_15HitTestLocationERKNS_11LayoutPointENS_13HitTestActionE
-}
-{
-   bug_417048b
-   Memcheck:Uninitialized
-   fun:_ZN5blink13InlineFlowBox45clearDescendantsHaveSameLineHeightAndBaselineEv
-   ...
-   fun:_ZN5blinkL25setLogicalWidthForTextRunEPNS_13RootInlineBoxEPNS_7BidiRunEPNS_10RenderTextEfRKNS*
-   fun:_ZN5blink15RenderBlockFlow41computeInlineDirectionPositionsForSegmentEPNS_13RootInlineBoxERKNS*
-   fun:_ZN5blink15RenderBlockFlow38computeInlineDirectionPositionsForLineEPNS_13RootInlineBoxERKNS*
-}
-{
-   bug_417048c
-   Memcheck:Uninitialized
-   fun:_ZNK5blink13InlineFlowBox35constrainToLineTopAndBottomIfNeededERNS_10LayoutRectE
-   fun:_ZN5blink13InlineFlowBox28paintBoxDecorationBackgroundERNS_9PaintInfoERKNS_11LayoutPointE
-   fun:_ZN5blink13InlineFlowBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-   fun:_ZN5blink13InlineFlowBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-   fun:_ZN5blink13RootInlineBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-   fun:_ZNK5blink18LineBoxListPainter5paintEPNS_20RenderBoxModelObjectERNS_9PaintInfoERKNS_11LayoutPointE
-}
-{
-   bug_417048d
-   Memcheck:Uninitialized
-   ...
-   fun:_ZNK5blink13RootInlineBox13maxLogicalTopEv
-   fun:_ZN5blinkL22computeUnderlineOffsetENS_21TextUnderlinePositionERKNS_11FontMetricsEPKNS_13InlineTextBoxEf
-   fun:_ZN5blink13InlineTextBox15paintDecorationEPNS_15GraphicsContextERKNS_10FloatPointENS_14TextDecorationE
-   fun:_ZN5blink13InlineTextBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-   fun:_ZN5blink13InlineFlowBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-   fun:_ZN5blink13RootInlineBox5paintERNS_9PaintInfoERKNS_11LayoutPointENS_10LayoutUnitES6_
-   fun:_ZNK5blink17RenderLineBoxList5paintEPNS_20RenderBoxModelObjectERNS_9PaintInfoERKNS_11LayoutPointE
-}
-{
    bug_417119
    Memcheck:Leak
    fun:_Znw*
@@ -3652,3 +3581,20 @@
    fun:_ZN5blink10UseCounterC1Ev
    fun:_ZN5blink4PageC1ERNS0_11PageClientsE
 }
+{
+   bug_484456
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN7content26GpuProcessTransportFactory23CreatePerCompositorDataEPN2ui10CompositorE
+   fun:_ZN7content26GpuProcessTransportFactory19CreateOutputSurfaceEN4base7WeakPtrIN2ui10CompositorEEE
+   fun:_ZN2ui10Compositor23RequestNewOutputSurfaceEv
+   fun:_ZN2cc13LayerTreeHost23RequestNewOutputSurfaceEv
+   fun:_ZN2cc17SingleThreadProxy23RequestNewOutputSurfaceEv
+}
+{
+   bug_484459
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN7content17ResourceScheduler15OnClientCreatedEiibb
+   fun:_ZN7content26ResourceDispatcherHostImpl23OnRenderViewHostCreatedEiibb
+}
diff --git a/tools/valgrind/memcheck/suppressions_linux.txt b/tools/valgrind/memcheck/suppressions_linux.txt
index 6d031be..cc14d2e 100644
--- a/tools/valgrind/memcheck/suppressions_linux.txt
+++ b/tools/valgrind/memcheck/suppressions_linux.txt
@@ -29,7 +29,7 @@
    fun:_ZN7content14RenderViewImpl22OnUpdateWebPreferencesERKNS_14WebPreferencesE
    fun:_ZN7content14RenderViewImpl20SetWebkitPreferencesERKNS_14WebPreferencesE
    fun:_ZThn*_N7content14RenderViewImpl20SetWebkitPreferencesERKNS_14WebPreferencesE
-   fun:_ZN7content16WebKitTestRunner5ResetEv
+   fun:_ZN7content15BlinkTestRunner5ResetEv
 }
 {
    bug_436292
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index ac9c687..d887a3f 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -286,5 +286,4 @@
    fun:_ZN2v88internal18StackFrameIterator5ResetEPNS0_14ThreadLocalTopE
    fun:_ZN2v88internal18StackFrameIteratorC2EPNS0_7IsolateE
    fun:_ZN2v88internal18StackFrameIteratorC1EPNS0_7IsolateE
-   fun:_ZN2v88internal7Isolate11FindHandlerEv
 }