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/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")